summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/Makefile1
-rw-r--r--app/acf-util/logon-controller.lua42
-rw-r--r--app/acf-util/logon-html.lsp34
-rw-r--r--app/acf-util/logon-model.lua138
-rw-r--r--app/acf-util/logon-status-html.lsp7
-rwxr-xr-xapp/acf-util/password-controller.lua12
-rw-r--r--app/acf-util/roles-controller.lua12
-rw-r--r--app/acf-util/roles-getlist-html.lsp16
-rw-r--r--app/acf-util/roles-model.lua16
-rw-r--r--app/acf-util/roles-read-html.lsp33
-rw-r--r--app/acf_www-controller.lua206
-rw-r--r--app/template-html.lsp54
-rw-r--r--app/welcome-controller.lua21
-rw-r--r--app/welcome-html.lsp2
-rw-r--r--lib/menubuilder.lua214
-rw-r--r--lib/roles.lua109
-rw-r--r--lib/session.lua95
-rw-r--r--roles13
-rwxr-xr-xwww/cgi-bin/mvc.lua83
19 files changed, 498 insertions, 610 deletions
diff --git a/app/Makefile b/app/Makefile
index 062832d..b71b10f 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -5,7 +5,6 @@ APP_DIST= \
acf-util/logon-html.lsp \
acf-util/logon-model.lua \
acf-util/logon-status-html.lsp \
- acf-util/logon-logout-html.lsp\
acf-util/roles-controller.lua \
acf-util/roles-getlist-html.lsp \
acf-util/roles-model.lua \
diff --git a/app/acf-util/logon-controller.lua b/app/acf-util/logon-controller.lua
index 75915fc..61b4864 100644
--- a/app/acf-util/logon-controller.lua
+++ b/app/acf-util/logon-controller.lua
@@ -2,30 +2,38 @@
module (..., package.seeall)
---require ("session")
-
+mvc = {}
mvc.on_load = function(self, parent)
- if (self.worker[self.conf.action] == nil ) or ( self.conf.action == "init" ) then
- self.worker[self.conf.action] = list_redir(self)
- end
- --logit ("logon.mvc.on_load activated")
- end
+ self.conf.default_action = "status"
+end
+-- Logon a new user based upon id and password in clientdata
logon = function(self)
- return ( {logon=self.model.logon(self, clientdata.userid, clientdata.password,clientdata.sessionid) })
+ local cmdresult
+ if clientdata.userid and clientdata.password then
+ local logon = self.model:logon(clientdata, conf.clientip, conf.sessiondir, sessiondata)
+ -- If successful logon, redirect to status, otherwise try again
+ if logon then
+ self.conf.action = "status"
+ self.conf.type = "redir"
+ error(self.conf)
+ else
+ cmdresult = "Logon Attempt Failed"
+ end
+ end
+ return ({ cmdresult = cmdresult })
end
+-- Log out current user and go to login screen
logout = function(self)
- local logout = self.model:logoff(clientdata.sessionid)
- if (logout) and (logout[1]) and (logout[1]["value"]) and (string.lower(logout[1]["value"]) == "successful") then
- self.conf.action = "logon"
- self.conf.type = "redir"
- error (self.conf)
- end
-
- return { logout = logout }
+ local logout = self.model.logoff(conf.sessiondir, sessiondata)
+ -- We have to redirect so a new session / menu is created
+ self.conf.action = "logon"
+ self.conf.type = "redir"
+ error (self.conf)
end
+-- Report the login status
status = function(self)
- return( {stats= self.model:status(clientdata.sessionid) })
+ return self.model.status(sessiondata)
end
diff --git a/app/acf-util/logon-html.lsp b/app/acf-util/logon-html.lsp
index 9a930a2..c1b4500 100644
--- a/app/acf-util/logon-html.lsp
+++ b/app/acf-util/logon-html.lsp
@@ -1,24 +1,20 @@
<? local form = ... ?>
-<h1>Logon</h1>
-<? --[[ ?>
-<?= html.cfe_unpack(form) ?>
-<? --]] ?>
+<? --[[
+ io.write(html.cfe_unpack(form))
+ --]] ?>
-<form action="<?= form.logon.option.script .. form.logon.option.prefix ..
- form.logon.option.controller .. "/" .. form.logon.option.action ?>" method="POST">
-<DL>
-<?
-local myform = form.logon.value
-for k,v in pairs(myform) do
- io.write("\t<DT")
- if (#v.errtxt > 0) then io.write(" class='error'") end
- io.write(">" .. v.label .. "</DT>\n")
+<? if form.cmdresult then ?>
+<h1>Command Result</h1>
+<p class='error'> <?= form.cmdresult ?></p>
+<? end ?>
- io.write("\t\t<DD>" .. html.form[v.type](v) .. "\n")
- if (v.descr) and (#v.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(v.descr, "\n", "<BR>") .. "</P>\n") end
- if (#v.errtxt > 0) then io.write("\t\t<P CLASS='error'>" .. string.gsub(v.errtxt, "\n", "<BR>") .. "</P>\n") end
- io.write("\t\t</DD>\n")
-end
-?>
+<h1>Logon</h1>
+<form action="logon" method="POST">
+<DL>
+ <DT>User id</DT>
+ <DD><input class="text" type="text" name="userid" value=""></DD>
+ <DT>Password</DT>
+ <DD><input class="password" type="password" name="password" value=""></DD>
+ <DT><input class="submit" type="submit" name="Logon" value="Logon"></DD>
</DL>
</form>
diff --git a/app/acf-util/logon-model.lua b/app/acf-util/logon-model.lua
index 33ffd56..cd840f7 100644
--- a/app/acf-util/logon-model.lua
+++ b/app/acf-util/logon-model.lua
@@ -19,113 +19,59 @@ else
auth = require ("authenticator-plaintext")
end
-logon = function (self, id_user, password_user,sessdata )
-local userid=cfe({ name="userid",label="User id", type="text" })
-local password=cfe({ name="password" ,label="Password", type="passwd"})
-local logon=cfe({ name="Logon", label="Logon", value="Logon", type="submit"})
-local s = ""
+-- Logoff the user by deleting session data
+logoff = function (sessiondir, sessiondata)
+ -- Unlink / delete the current session
+ local result = session.unlink_session(sessiondir, sessiondata.id)
+ -- Clear the current session data
+ for a,b in pairs(sessiondata) do
+ sessiondata[a] = nil
+ end
-local csess = session.check_session(conf.sessiondir, sessdata)
-if csess ~= "an unknown user" then
-session.unlink_session(conf.sessiondir, sessdata)
-for a,b in pairs(sessiondata) do
-if a ~= "menu" then
-sessiondata[a] = nil
-end
+ return (result)
end
-sessiondata.id = session.random_hash(512)
-build_menus(self)
-end
-
-local counteven = session.count_events(conf.sessiondir, id_user, session.hash_ip_addr(ENV["REMOTE_ADDR"]))
-if counteven then
-userid.errtxt="Information not recognized"
-return (cfe {type="form",
- option={script=ENV["SCRIPT_NAME"],
- prefix=self.conf.prefix,
- controller=self.conf.controller,
- action="logon" },
- value={userid,password,logon},testme={counteven}
- })
-end
+-- Log on new user if possible and set up userinfo in session
+-- if we fail, we leave the session alone (don't log out)
+logon = function (self, clientdata, ip_addr, sessiondir, sessiondata)
+ -- Check to see if we can login this user id / ip addr
+ local countevent = session.count_events(sessiondir, clientdata.userid, session.hash_ip_addr(ip_addr))
+ if countevent then
+ session.record_event(sessiondir, clientdata.userid, session.hash_ip_addr(ip_addr))
+ return (false)
+ end
-session.expired_events(conf.sessiondir)
- if id_user and password_user then
- local password_user_md5 = fs.md5sum_string(password_user)
- if auth.authenticate (self, id_user, password_user_md5) then
- local t = auth.get_userinfo (self, id_user)
+ if clientdata.userid and clientdata.password then
+ local password_user_md5 = fs.md5sum_string(clientdata.password)
+ if auth.authenticate (self, clientdata.userid, password_user_md5) then
+ -- We have a successful login, change sessiondata
+ -- for some reason, can't call this function or it skips rest of logon
+ -- logout(sessiondir, sessiondata)
+ ---[[ so, do this instead
+ session.unlink_session(sessiondir, sessiondata.id)
+ -- Clear the current session data
+ for a,b in pairs(sessiondata) do
+ if a ~= "id" then sessiondata[a] = nil end
+ end
+ --]]
sessiondata.id = session.random_hash(512)
+ local t = auth.get_userinfo (self, clientdata.userid)
sessiondata.userinfo = t or {}
- sessiondata.userinfo.perm = roles.get_roles_perm(self,auth.get_userinfo_roles(self,id_user))
- self.conf.prefix="/acf-util/"
- self.conf.action="status"
- self.conf.type="redir"
- self.conf.controller="logon"
- error(self.conf)
+ return (true)
else
- userid.errtxt = "Information not recognized"
- session.record_event(conf.sessiondir, id_user, session.hash_ip_addr(ENV["REMOTE_ADDR"]))
- return (cfe {type="form",
- option={script=ENV["SCRIPT_NAME"],
- prefix=self.conf.prefix,
- controller=self.conf.controller,
- action="logon" },
- value={userid,password,logon},testme={counteven}
- })
+ -- We have a bad login, log the event
+ session.record_event(sessiondir, clientdata.userid, session.hash_ip_addr(ip_addr))
end
- else
- return ( cfe{ type="form",
- option={script=ENV["SCRIPT_NAME"],
- prefix=self.conf.prefix,
- controller=self.conf.controller,
- action="logon" } ,
- value={userid,password,logon},testme={counteven}
- })
end
+ return (false)
end
-
- -- logged on?
- -- record event and ignore the attempt
- -- too many attempts for this ip?
- -- record event and ignore the attempt
- -- too many attempts for this user?
- -- record event and ignore the attempt
- -- uname/passwd invalid?
- -- record event and ignore the attempt
- -- All ok?
- -- look up their role, issue new session
-
- --this goes through and will return true or false if limit reached
-logoff = function (self, sessdata)
- -- sessionid invalid?
- -- record event, ignore the attempt
- -- else
- -- unlink session
- -- issue new sessionid
-
- --made it so that we get a new sessionid then try to delete it
- --need to make the whole sessiondata table go bye bye
- delsess = session.unlink_session(conf.sessiondir, sessdata)
- if delsess == true then
- logoff = "Successful"
- else
- logoff = "Incomplete or Unsuccessful logoff"
- end
- for a,b in pairs(sessiondata) do
- if a ~= "menu" then
- sessiondata[a] = nil
+-- Return the session id and username
+status = function(sessiondata)
+ local name = "unknown"
+ if sessiondata.userinfo and sessiondata.userinfo.username then
+ name = sessiondata.userinfo.username
end
- end
- sessiondata.id = session.random_hash(512)
- build_menus(self)
- return ( cfe{ {value=logoff,name="logoff"},{value=sessiondata,name="sessiondata"} })
-end
-
-status = function(self, sessdata)
- sessid = sessdata
- checkme = session.check_session(self.conf.sessiondir,sessdata)
- return ( cfe { checkme={value=checkme,name="checkme"}, sessid={value=sessid,name="sessid" } })
+ return ( { sessionid = sessiondata.id, username = name } )
end
diff --git a/app/acf-util/logon-status-html.lsp b/app/acf-util/logon-status-html.lsp
index 3524716..072051d 100644
--- a/app/acf-util/logon-status-html.lsp
+++ b/app/acf-util/logon-status-html.lsp
@@ -1,5 +1,8 @@
<? local view= ... ?>
+<? --[[
+ io.write(html.cfe_unpack(view))
+--]] ?>
<h1>User Status </h1>
<p> Below is your current Session id <p>
-<?= view.stats.sessid.value ?>
-<p>You are currently known to the system as <?= view.stats.checkme.value ?>.</p>
+<?= view.sessionid ?>
+<p>You are currently known to the system as <?= view.username ?>.</p>
diff --git a/app/acf-util/password-controller.lua b/app/acf-util/password-controller.lua
index 185c3e4..f891c58 100755
--- a/app/acf-util/password-controller.lua
+++ b/app/acf-util/password-controller.lua
@@ -1,18 +1,10 @@
module(..., package.seeall)
-auth=require("authenticator-plaintext")
-
-local list_redir = function (self)
- self.conf.action = "status"
- self.conf.type = "redir"
- error (self.conf)
-end
+local auth=require("authenticator-plaintext")
mvc = {}
mvc.on_load = function(self, parent)
- if (self.worker[self.conf.action] == nil ) or ( self.conf.action == "init" ) then
- self.worker[self.conf.action] = list_redir(self)
- end
+ self.conf.default_action = "status"
end
local function admin_permission()
diff --git a/app/acf-util/roles-controller.lua b/app/acf-util/roles-controller.lua
index b8fa7f4..4cf1937 100644
--- a/app/acf-util/roles-controller.lua
+++ b/app/acf-util/roles-controller.lua
@@ -2,17 +2,9 @@
module (..., package.seeall)
---require ("session")
-
-mvc.on_load = function(self, parent)
- if (self.worker[self.conf.action] == nil ) or ( self.conf.action == "init" ) then
- self.worker[self.conf.action] = list_redir(self)
- end
- --logit ("logon.mvc.on_load activated")
- end
-
read = function(self)
- return( {read= self.model:read(clientdata.sessionid)})
+ --return( {read= self.model:read(clientdata.sessionid)})
+ return ( { userid = self.sessiondata.userinfo.userid, roles = self.sessiondata.userinfo.roles, permissions = self.sessiondata.permissions } )
end
getlist = function(self)
diff --git a/app/acf-util/roles-getlist-html.lsp b/app/acf-util/roles-getlist-html.lsp
index 48c2aba..25d8d62 100644
--- a/app/acf-util/roles-getlist-html.lsp
+++ b/app/acf-util/roles-getlist-html.lsp
@@ -1,7 +1,13 @@
<? local view= ... ?>
+<? --[[
+ io.write(html.cfe_unpack(view))
+--]] ?>
+
<h1>Controller Status</h1>
-<? for a,b in pairs(view.contlist.value) do
-print("<b>",a,"</b>")
-for k,v in pairs(b) do print(v) end
-print("<br>")
-end ?>
+<? ---[[
+for a,b in pairs(view.contlist) do
+ print("<b>",a,"</b>")
+ for k,v in pairs(b) do print(v) end
+ print("<br>")
+end
+--]] ?>
diff --git a/app/acf-util/roles-model.lua b/app/acf-util/roles-model.lua
index 95f28d1..c3ce2c7 100644
--- a/app/acf-util/roles-model.lua
+++ b/app/acf-util/roles-model.lua
@@ -1,27 +1,17 @@
-- Roles/Group model functions
-require ("session")
require ("roles")
module (..., package.seeall)
-read = function(self,sessionid)
- useid , theroles = session.check_session(conf.sessiondir,sessionid,"roles")
---we need to expand roles to give us real perm list
- perm = roles.get_roles_perm(self,theroles)
- return ( cfe { userid={value=useid,name="userid"},roles={ value=theroles,name="roles"}, perm={value=perm,name="perm"},{value=self.conf,name="self"},{value=sessiondata.userinfo.perm,name="perm2"} })
-end
-
getcont = function(self)
--need to get a list of all the controllers
- --t = roles.get_controllers(self,"skins")
- bobo = roles.get_controllers(self)
+ controllers = roles.get_controllers(self)
local table_m = {}
- for a,b in pairs(bobo) do
+ for a,b in pairs(controllers) do
temp = roles.get_controllers_func(self,b)
table_m[b.sname] = temp
end
- return (cfe {value=table_m,name="mtable"})
-
+ return (table_m)
end
diff --git a/app/acf-util/roles-read-html.lsp b/app/acf-util/roles-read-html.lsp
index c5ea541..ddda93a 100644
--- a/app/acf-util/roles-read-html.lsp
+++ b/app/acf-util/roles-read-html.lsp
@@ -1,11 +1,28 @@
<? local view= ... ?>
-<h1>Role Views</h1>
-<p>Roles/Permission list for <?= view.read.userid.value ?>:<p>
+<? --[[
+ io.write(html.cfe_unpack(view))
+--]] ?>
-<p>You are valid in these role <p>
-<? for a,b in pairs(view.read.roles.value) do
-print("<li>",b) end ?>
+<? ---[[ ?>
+<H1>Roles/Permission list for <?= view.userid ?>:</H1>
-<p>Your full permissions are<p>
-<?= view.read.perm.value ?>
-<?= html.cfe_unpack(view) ?>
+<? if view.roles then ?>
+ <H2>You are valid in these roles</H2>
+ <? for a,b in pairs(view.roles) do
+ print("<li>",b,"</li>")
+ end ?>
+<? end ?>
+<? --]] ?>
+
+<? ---[[ ?>
+<? if view.permissions then ?>
+ <H2>Your full permissions are</H2>
+ <? for x,cont in pairs(view.permissions) do
+ print("<b>",x,"</b>")
+ for y,act in pairs(cont) do
+ print(y)
+ end
+ print("<br>")
+ end ?>
+<? end ?>
+<? --]] ?>
diff --git a/app/acf_www-controller.lua b/app/acf_www-controller.lua
index 59c3f72..0dfbea7 100644
--- a/app/acf_www-controller.lua
+++ b/app/acf_www-controller.lua
@@ -15,82 +15,47 @@ require "posix"
-- We use the parent exception handler in a last-case situation
local parent_exception_handler
-function build_menus(self)
- --Build the menu
+local function build_menus(self)
m=require("menubuilder")
roll = require ("roles")
- form = require ("format")
- sessiondata.menu = {}
- sessiondata.menu.mainmenu = m.get_menuitems(self.conf.appdir)
- sessiondata.menu.submenu = m.get_submenuitems(self.conf.appdir)
-
-local temp
-if sessiondata.userinfo == nil then
- --we are dealing with an unknown user
-p = {"ANONYMOUS"}
- --this will be whatever the "UNKNOWN" role is ... right now it is ANONYMOUS
- --temp should be the
-temp = format.string_to_table(roll.get_roles_perm(self,p),",")
-else
- --we don't need to figure out what permission have it is in sessiondata
-temp = format.string_to_table(sessiondata.userinfo.perm,",")
-end
- --lets apply permissions
- for a,b in pairs(sessiondata.menu.mainmenu) do
- for k,v in pairs(temp) do
- local control,acti = string.match(v,"(%a+):(%a+)")
- if sessiondata.menu.mainmenu[a].controller == control then
- if sessiondata.menu.mainmenu[a].action == acti then
- sessiondata.menu.mainmenu[a].match = "yes"
- break
- else
- sessiondata.menu.mainmenu[a].match = "no"
- end
- else
- sessiondata.menu.mainmenu[a].match = "no"
- end
- if sessiondata.menu.mainmenu[a].controller == "menuhints" then
- sessiondata.menu.mainmenu[a].match = "yes"
- end
- end
+ -- Build the permissions table
+ local roles = {}
+ if sessiondata.userinfo and sessiondata.userinfo.roles then
+ roles = sessiondata.userinfo.roles
end
- --also need to do the submenu tabs... this is only for appearence
- --will have to make sure somewhere else they can't run them :)
- for a,b in pairs(sessiondata.menu.submenu) do
- for c,d in pairs(sessiondata.menu.submenu[a]) do
- for k,v in pairs(temp) do
- local control,acti = string.match(v,"(%a+):(%a+)")
- if (a == control) then
- if sessiondata.menu.submenu[a][c].action == acti then
- sessiondata.menu.submenu[a][c].match = "yes"
- break
+ local permissions = roll.get_roles_perm(self.conf.appdir,roles)
+ sessiondata.permissions = permissions
+
+ --Build the menu
+ local cats = m.get_menuitems(self.conf.appdir)
+ -- now, loop through menu and remove actions without permission
+ -- go in reverse so we can remove entries while looping
+ for x = #cats,1,-1 do
+ local cat = cats[x]
+ for y = #cat.groups,1,-1 do
+ local group = cat.groups[y]
+ if nil == permissions[group.controller] then
+ table.remove(cat.groups, y)
else
- sessiondata.menu.submenu[a][c].match = "no"
- end
+ for z = #group.tabs,1,-1 do
+ local tab = group.tabs[z]
+ if nil == permissions[group.controller][tab.action] then
+ table.remove(group.tabs, z)
+ end
+ end
+ if 0 == #group.tabs then
+ table.remove(cat.groups, y)
+ end
end
- end
- end
- end
-
- local temptab = {}
- for a,b in pairs(sessiondata.menu.mainmenu) do
- if sessiondata.menu.mainmenu[a].match ~= "no" then
- temptab[#temptab +1 ] = sessiondata.menu.mainmenu[a]
- end
- end
-
- sessiondata.menu.mainmenu = temptab
- local tempsub = {}
- for c,d in pairs(sessiondata.menu.submenu) do
- for e,f in pairs(sessiondata.menu.submenu[c]) do
- if sessiondata.menu.submenu[c][e].match ~= "no" then
- if not (tempsub[c]) then tempsub[c] = {} end
- tempsub[c][#tempsub[c] +1] = sessiondata.menu.submenu[c][e]
end
- end
+ if 0 == #cat.groups then
+ table.remove(cats, x)
+ end
end
- sessiondata.menu.submenu = tempsub
+ sessiondata.menu = {}
+ sessiondata.menu.cats = cats
+
-- Debug: Timestamp on menu creation
sessiondata.menu.timestamp = {tab="Menu_created: " .. os.date(),action="Menu_created: " .. os.date(),}
end
@@ -104,7 +69,8 @@ mvc.on_load = function (self, parent)
self.conf.libdir = self.conf.libdir or ( self.conf.appdir .. "/lib/" )
self.conf.sessiondir = self.conf.sessiondir or "/tmp/"
self.conf.appuri = "https://" .. ENV.HTTP_HOST .. ENV.SCRIPT_NAME
- self.conf.default_controller = "welcome"
+ self.conf.default_controller = "welcome"
+ self.conf.default_action = "read"
self.clientdata = FORM
self.conf.clientip = ENV.REMOTE_ADDR
@@ -115,68 +81,66 @@ mvc.on_load = function (self, parent)
sessionlib=require ("session")
+ -- before we look at sessions, remove old sessions and events
+ -- this prevents us from giving a "session timeout" message, but I'm ok with that
+ sessionlib.expired_events(self.conf.sessiondir)
+ -- Load the session data
+ self.sessiondata = nil
self.sessiondata = {}
-
- local tempid = ""
- if self.clientdata.sessionid == nil then
- self.sessiondata.id = sessionlib.random_hash(512)
- tempid = self.sessiondata.id
- if not (self.sessiondata.menu) then
- build_menus(self)
- end
-
- else
+ if nil ~= self.clientdata.sessionid then
+ logevent("Found session id = " .. self.clientdata.sessionid)
+ -- Load existing session data
local timestamp
- tempid = self.clientdata.sessionid
timestamp, self.sessiondata =
sessionlib.load_session(self.conf.sessiondir,
self.clientdata.sessionid)
- build_menus(self)
if timestamp == nil then
- self.sessiondata.id = tempid
+ -- invalid session id, report event and create new one
sessionlib.record_event(self.conf.sessiondir,
sessionlib.hash_ip_addr(self.conf.clientip))
- build_menus(self)
+ logevent("Didn't find session")
else
-
- -- FIXME: This is probably wrong place to generate the menus
-
- local now = os.time()
- local minutes_ago = now - (sessionlib.minutes_expired_events * 60)
- if timestamp < minutes_ago then
- sessionlib.unlink_session(self.conf.sessiondir, self.clientdata.sessionid)
- sessiondata.id = sessionlib.random_hash(512)
- sessionlib.count_events(self.conf.sessiondir,self.conf.userid or "", sessionlib.hash_ip_addr(self.conf.clientip),sessionlib.limit_count_events)
- --[[
- FIXME --- need to write this function
- if too many bad events for this ip invaidate the session
-
- if (timestamp is > 10 minutes old)
- sessionlib.unlink.session (self.conf.sessiondir,
- self.sessiondata.id)
- self.sessiondata = {}
- self.sessiondata.id = sessionlib.random_hash(512)
- generate flash message "Inactivity logout"
- end
- ]]--
- sessionlib.expired_events(self.conf.sessiondir,sessionlib.minutes_expired_events)
- build_menus(self)
+ logevent("Found session")
+ -- We read in a valid session, check if it's ok
+ if sessionlib.count_events(self.conf.sessiondir,self.conf.userid or "", sessionlib.hash_ip_addr(self.conf.clientip)) then
+ logevent("Bad session, erasing")
+ -- Too many events on this id / ip, kill the session
+ sessionlib.unlink_session(self.conf.sessiondir, self.clientdata.sessionid)
+ self.sessiondata.id = nil
end
end
end
+
+ if nil == self.sessiondata.id then
+ self.sessiondata = {}
+ self.sessiondata.id = sessionlib.random_hash(512)
+ logevent("New session = " .. self.sessiondata.id)
+ end
+ if nil == self.sessiondata.permissions or nil == self.sessiondata.menu then
+ logevent("Build menus")
+ build_menus(self)
+ end
end
+mvc.check_permission = function(self, controller, action)
+ logevent("Trying " .. (controller or "nil") .. ":" .. (action or "nil"))
+ if nil == self.sessiondata.permissions then return false end
+ if controller then
+ if nil == self.sessiondata.permissions[controller] then return false end
+ if action and nil == self.sessiondata.permissions[controller][action] then return false end
+ end
+ return true
+end
mvc.post_exec = function (self)
sessionlib=require ("session")
-- sessionlib.serialize("s", sessiondata))
if sessiondata.id then
- sessionlib.save_session(conf.sessiondir,
- sessiondata.id, sessiondata)
+ sessionlib.save_session(conf.sessiondir, sessiondata)
end
-- Close the logfile
- conf.logfile:close()
+ conf.logfile:close()
end
@@ -249,15 +213,13 @@ view_resolver = function(self)
local m,worker_loaded,model_loaded = self:new("alpine-baselayout/hostname")
local alpineversion = self:new("alpine-baselayout/alpineversion")
- -- FIXME - this is ugly, but it puts the hostname the expected
- -- format if the controller doesn't load correctly
- local h = {}
-
-- If the worker and model loaded correctly, then
-- use the sub-controller
+ local h
if worker_loaded and model_loaded then
h = m.worker.read(m)
else
+ h = {}
h.hostname = { value = "unknown" }
end
@@ -273,18 +235,9 @@ view_resolver = function(self)
skin = self.conf.skin or ""
}
- -- Fetch the menu's from sessiondata (filter out what's needed)
- local menu = self.sessiondata.menu.mainmenu
- local submenu = self.sessiondata.menu.submenu[pageinfo.controller]
-
---[[ -- DEBUG: Next row's is to display when the menu was created (see function build_menus(self) in BOF)
- if (submenu) then
- submenu[99] = sessiondata.menu.timestamp
- end
---]]
return function (viewtable)
local template = haserl.loadfile (template)
- return template ( pageinfo, menu, submenu, viewtable, self.sessiondata )
+ return template ( pageinfo, viewtable, self.sessiondata )
end
end
@@ -298,7 +251,10 @@ end
exception_handler = function (self, message )
local html = require ("html")
- mvc.post_exec (self)
+ pcall(function()
+ if sessiondata.id then logevent("Redirecting " .. sessiondata.id) end
+ mvc.post_exec (self)
+ end) -- don't want exceptions from this
if type(message) == "table" then
if message.type == "redir" then
io.write ("Status: 302 Moved\n")
@@ -315,7 +271,7 @@ exception_handler = function (self, message )
elseif message.type == "dispatch" then
parent_exception_handler(self, message)
end
- else
+ else
parent_exception_handler( self, message)
end
end
diff --git a/app/template-html.lsp b/app/template-html.lsp
index 473674a..cbb5c29 100644
--- a/app/template-html.lsp
+++ b/app/template-html.lsp
@@ -1,6 +1,5 @@
-<? local pageinfo , mainmenu, submenu, viewtable, session = ...
- html=require("html")
- sess=require("session") ?>
+<? local pageinfo , viewtable, session = ...
+ html=require("html") ?>
Status: 200 OK
Content-Type: text/html
<? if (session.id) then
@@ -38,11 +37,10 @@ Content-Type: text/html
<p>
<? local ctlr = pageinfo.script .. "/acf-util/logon/"
- sname = sess.check_session("/tmp", session.id)
- if sname == "an unknown user" then
- io.write ( string.format("\t\t\t\t\t\t<a href=\"%s\">Log in</a>\n", ctlr .. "logon" ) )
+ if session.userinfo and session.userinfo.userid then
+ io.write ( string.format("\t\t\t\t\t\t<a href=\"%s\">Log out as '" .. session.userinfo.userid .. "'</a>\n", ctlr .. "logout" ) )
else
- io.write ( string.format("\t\t\t\t\t\t<a href=\"%s\">Log out as '" .. sname .. "'</a>\n", ctlr .. "logout" ) )
+ io.write ( string.format("\t\t\t\t\t\t<a href=\"%s\">Log in</a>\n", ctlr .. "logon" ) )
end ?>
|
<a href="/">home</a> |
@@ -61,37 +59,25 @@ Content-Type: text/html
</div>
<?
- -- FIXME: This needs to go in a library function somewhere (menubuilder?)
+ local class
+ local tabs
io.write ( "<ul>")
-
- local cat, group
- local class
- for k,v in ipairs(mainmenu) do
- if v.cat ~= cat then
- if not (cat == nil) and not (cat == "") then
- io.write ("\t\t\t\t\t</ul>")
- end
- cat = v.cat
- if (cat ~= "") then -- Filter out empty categories
- io.write (string.format("\n\t\t\t\t<li>%s\n\t\t\t\t\t<ul>\n", cat)) --start row
- end
- group = ""
- end
- if v.group ~= group then
- group = v.group
- if pageinfo.prefix == v.prefix .. "/" and
- pageinfo.controller == v.controller then
+ for x,cat in ipairs(session.menu.cats) do
+ io.write (string.format("\n\t\t\t\t<li>%s\n\t\t\t\t\t<ul>\n", cat.name)) --start row
+ for y,group in ipairs(cat.groups) do
+ if pageinfo.prefix == group.prefix .. '/' and pageinfo.controller == group.controller then
class="class='selected'"
+ tabs = group.tabs
else
class=""
end
io.write (string.format("\t\t\t\t\t\t<li %s><a href=\"%s%s/%s/%s\">%s</a></li>\n",
- class,ENV.SCRIPT_NAME,v.prefix, v.controller, v.action, v.group ))
+ class,ENV.SCRIPT_NAME,group.prefix, group.controller, group.tabs[1].action, group.name ))
end
- end ?>
- </ul>
- </li>
- </ul>
+ io.write ( "\t\t\t\t\t</ul>" )
+ end
+ io.write ( "\n\t\t\t\t</li>\n\t\t\t</ul>\n")
+ ?>
<div class="tailer">
</div>
@@ -116,13 +102,13 @@ Content-Type: text/html
</div>
<? local class="" ?>
- <? for k,v in pairs(submenu or {}) do
- if submenu[k]["action"] == pageinfo.action then
+ <? for x,tab in pairs(tabs or {}) do
+ if tab.action == pageinfo.action then
class="class='selected'"
else
class=""
end
- io.write (string.format('\t\t\t<a %s href="%s">%s</a>\n',class,submenu[k]["action"],submenu[k]["tab"] ))
+ io.write (string.format('\t\t\t<a %s href="%s">%s</a>\n',class,tab.action,tab.name ))
end
?>
diff --git a/app/welcome-controller.lua b/app/welcome-controller.lua
index 450952c..3ff5cc5 100644
--- a/app/welcome-controller.lua
+++ b/app/welcome-controller.lua
@@ -1,27 +1,8 @@
-- A standin controller for testing
-
module (..., package.seeall)
--- Cause an http redirect to our "read" action
--- We use the self.conf table because it already has prefix,controller,etc
--- The redir code is defined in the application error handler (acf-controller)
-local list_redir = function (self)
- self.conf.action = "read"
- self.conf.type = "redir"
- error (self.conf)
-end
-
-mvc = {}
-mvc.on_load = function(self, parent)
- -- It doesn't matter what action they choose - we only support read
- if ( self.conf.action ~= "read") then
- list_redir(self)
- end
-end
-
-
read = function (self )
- return ( { } )
+ return ( {self = self} )
end
diff --git a/app/welcome-html.lsp b/app/welcome-html.lsp
index 7f205fe..b961a83 100644
--- a/app/welcome-html.lsp
+++ b/app/welcome-html.lsp
@@ -1,3 +1,5 @@
<? view = ... ?>
<h1>Alpine Configuration Framework</h1>
<p>Welcome.</p>
+
+<? io.write(html.cfe_unpack(view)) ?>
diff --git a/lib/menubuilder.lua b/lib/menubuilder.lua
index 1d4c974..c7ff075 100644
--- a/lib/menubuilder.lua
+++ b/lib/menubuilder.lua
@@ -10,157 +10,115 @@ module(..., package.seeall)
-- startdir should be the app dir.
local get_candidates = function (startdir)
local t = {}
- startdir = startdir .. "/"
local fh = io.popen('find ' .. startdir .. ' -name "*.menu"')
-
- local start = string.gsub(startdir, "/$", "")
for x in fh:lines() do
- table.insert (t, (string.gsub(x, start, "")))
+ t[#t + 1] = x
end
-
return t
end
+-- Split string into priority and name, convert '_' to space
+local parse_menu_entry = function (entry)
+ local name, priority
+ if (string.match(entry, "^%d")) then
+ priority, name = string.match(entry, "(%d+)(.*)")
+ else
+ name = entry
+ end
+ name = string.gsub(name, "_", " ")
+ return name, priority
+end
--- internal function for table.sort
-local t_compare = function (x,y,f)
- for k,v in pairs(f) do
- local a = x[v]
- local b = y[v]
- if tonumber(a) and tonumber(b) then
- a=tonumber(a)
- b=tonumber(b)
- end
- if a < b then return true end
- if a > b then return false end
+-- Parse menu file entry, returning cat, group, tab, action and priorities
+local parse_menu_line = function (line)
+ local result = nil
+ --skip comments and blank lines
+ if nil == (string.match(line, "^#") or string.match(line,"^$")) then
+ local item = {}
+ for i in string.gmatch(line, "%S+") do
+ item[#item + 1] = i
end
- return false
- end
-
--- Returns a table of all submenu items found
--- Displayorder of the tabs comes from the order in the .menu files
-get_submenuitems = function (startdir)
- local t = {}
- local menuitems = get_menuitems(startdir)
-
- for k,v in pairs(menuitems) do
- if (menuitems[k]["tab"] ~= "") then
- if not (t[menuitems[k]["controller"]]) then t[menuitems[k]["controller"]] = {} end
- table.insert (t[menuitems[k]["controller"]], {tab=menuitems[k]["tab"],action=menuitems[k]["action"]})
+ if #item >= 1 then
+ result = {}
+ result.cat, result.cat_prio = parse_menu_entry(item[1])
+ if (item[2]) then result.group, result.group_prio = parse_menu_entry(item[2]) end
+ if (item[3]) then result.tab = parse_menu_entry(item[3]) end
+ if (item[4]) then result.action = parse_menu_entry(item[4]) end
end
end
+ return result
+end
- return t
+-- Function to compare priorities, missing priority moves to the front, same priority sorted alphabetically
+local prio_compare = function(x,y)
+ if x.priority == y.priority then
+ if x.name < y.name then return true end
+ return false
+ end
+ if nil == x.priority then return true end
+ if nil == y.priority then return false end
+ if tonumber(x.priority) < tonumber(y.priority) then return true end
+ return false
end
-- returns a table of all the menu items found, sorted by priority
--- Table format: prefix controller cat group tab action
get_menuitems = function (startdir)
- local t = {}
- for k,v in pairs(get_candidates(startdir)) do
- local prefix, controller = mvc.dirname(v), mvc.basename(v, ".menu")
- -- open the thing, and parse the contents
- local fh = io.open(startdir .. "/" .. v)
- local prio = 10
- for x in fh:lines() do
- local c = string.match(x, "^#") or string.match(x,"^$")
- if c == nil then
- local item = {}
- for i in string.gmatch(x, "%S+") do
- table.insert(item, i)
+ local cats = {}
+ local reversecats = {}
+ startdir = (string.gsub(startdir, "/$", "")) --remove trailing /
+ for k,filename in pairs(get_candidates(startdir)) do
+ local controller = mvc.basename(filename, ".menu")
+ local prefix = (string.gsub(mvc.dirname(filename), startdir, ""))
+
+ -- open the menu file, and parse the contents
+ local handle = io.open(filename)
+ for x in handle:lines() do
+ local result = parse_menu_line(x)
+ if result then
+ for i = 1,1 do -- loop so break works
+ -- Add the category
+ if nil == reversecats[result.cat] then
+ table.insert ( cats,
+ { name=result.cat,
+ groups = {},
+ reversegroups = {} } )
+ reversecats[result.cat] = #cats
+ end
+ local cat = cats[reversecats[result.cat]]
+ cat.priority = cat.priority or result.cat_prio
+ -- Add the group
+ if nil == result.group then break end
+ if nil == cat.groups[cat.reversegroups[result.group]] then
+ table.insert ( cat.groups,
+ { name = result.group,
+ controller = controller,
+ prefix = prefix,
+ tabs = {} } )
+ cat.reversegroups[result.group] = #cat.groups
+ end
+ local group = cat.groups[cat.reversegroups[result.group]]
+ group.priority = group.priority or result.group_prio
+ -- Add the tab
+ if nil == result.tab or nil == result.action then break end
+ local tab = { name = result.tab, action = result.action }
+ table.insert(group.tabs, tab)
end
- table.insert(t, { prefix=prefix,
- controller=controller,
- catprio="nan",
- cat=item[1] or "",
- groupprio="nan",
- group=item[2] or "",
- tabprio=tostring(prio),
- tab=item[3] or "",
- action=item[4] or "" })
- prio=prio+5
- end
- end
- fh:close()
- end
- -- Ok, we now have the raw menu table
- -- now try to parse out numbers in front of any cat, group or tabs
- for x in ipairs(t) do
- local f = t[x]
- if (string.match(f.cat, "^%d")) then
- f.catprio, f.cat = string.match(f.cat, "(%d+)(.*)")
- end
- if (string.match(f.group, "^%d")) then
- f.groupprio, f.group = string.match(f.group, "(%d+)(.*)")
- end
- if (string.match(f.tab, "^%d")) then
- f.tabprio, f.tab = string.match(f.tab, "(%d+)(.*)")
- end
- end
-
- -- Convert underscores to spaces
- for x in ipairs(t) do
- t[x].cat = string.gsub(t[x].cat, "_", " ")
- t[x].group = string.gsub(t[x].group, "_", " ")
- t[x].tab = string.gsub(t[x].tab, "_", " ")
- end
-
- -- Now alpha sort
- table.sort(t, function(x,y)
- return t_compare (x,y,{"cat", "catprio", "group", "groupprio", "tab", "tabprio"} )
- end)
-
- -- Fill in the priorities
- local fill_prio = function (t, start, stop, col)
- local prio = t[start][col]
- if prio == "nan" then prio = "0" end
- while start <= stop do
- t[start][col] = prio
- start = start + 1
- end
- end
-
-
--- Fill in the priorities
--- Warning - UGLY code ahead.
--- Basic rules, for each cat and group, if the prio is nan, then set it
--- to the lowest value for that group or cat.
- local k = 1
- while ( k <= table.maxn(t) ) do
- local c = k
- while ( c <= table.maxn(t) and t[c].cat == t[k].cat ) do
- c=c+1
- end
- c=c-1 -- back up one - we only want whats the same
- fill_prio(t,k,c,"catprio")
- -- from k,c is a mini table, do the same for groupprio
- local g = k
- while ( g <= c ) do
- local h = g
- while ( h <= c and t[h].group == t[g].group ) do
- h=h+1
end
- h=h-1 --- back up one (again)
- fill_prio(t,g,h,"groupprio")
- g=h+1
end
- k = c + 1
+ handle:close()
end
-
- -- Now priority sort
- table.sort(t, function(x,y)
- return t_compare (x,y,{"catprio", "cat", "groupprio", "group", "tabprio", "tab"} )
- end)
+ -- Now that we have the entire menu, sort by priority
+ -- Categories first
+ table.sort(cats, prio_compare)
- -- drop the priorities - they were internal
- for k,v in ipairs(t) do
- v.catprio = nil
- v.groupprio = nil
- v.tabprio = nil
+ -- Then groups
+ for x, cat in ipairs(cats) do
+ cat.reversegroups = nil -- don't need reverse table anymore
+ table.sort(cat.groups, prio_compare)
end
- return t
+ return cats
end
diff --git a/lib/roles.lua b/lib/roles.lua
index bdaf635..806be67 100644
--- a/lib/roles.lua
+++ b/lib/roles.lua
@@ -7,75 +7,102 @@ require ("format")
module (..., package.seeall)
+-- Return a list of *controller.lua files
list_controllers = function(self)
-local list = {}
-local f = io.popen("/usr/bin/find /usr/share/acf/ |/bin/grep \"controller.lua$\" ")
- for a in f:lines() do
- list[#list + 1 ] = a
- end
-f:close()
-return list
+ local list = {}
+ local f = io.popen("/usr/bin/find /usr/share/acf/ |/bin/grep \"controller.lua$\" ")
+ for a in f:lines() do
+ list[#list + 1 ] = a
+ end
+ f:close()
+ return list
end
+-- Return information about all or specified controller files
get_controllers = function(self,controller)
--we get all the controllers
local list = roles.list_controllers()
--we need to grab the directory and name of file
local temp = {}
for k,v in pairs(list) do
- path = string.match(v,"[/%w-]+/")
- filename = string.match(v,"[^/]*.lua")
- name = string.match(filename,"[^.]*")
- sname = string.match(filename,"[^-]*")
- temp[sname] = {path=path,filename=filename,name=name,sname=sname}
+ path = string.match(v,"[/%w-]+/")
+ filename = string.match(v,"[^/]*.lua")
+ name = string.match(filename,"[^.]*")
+ sname = string.match(filename,"[^-]*")
+ temp[sname] = {path=path,filename=filename,name=name,sname=sname}
+ end
+ if controller then
+ return temp[controller]
+ else
+ return temp
end
- if controller then
- return temp[controller]
- else
- return temp
- end
-
end
+-- Find all public functions in a controller
get_controllers_func = function(self,controller_info)
if controller_info == nil then
- return "Could not be processed"
+ return "Could not be processed"
else
package.path=package.path .. ";" .. controller_info.path .. "?.lua"
temp = require (controller_info.name)
temp1 = {}
for a,b in pairs(temp) do
- local c = string.match(a,"mvc") or string.match(a,"^_")
- if c == nil then
- temp1[#temp1 +1] = a
+ local c = string.match(a,"mvc") or string.match(a,"^_")
+ if c == nil then
+ temp1[#temp1 +1] = a
+ end
end
-end
--require (controller_info.name)
--we need to go through bobo and take out the mvc func and locals and --
return temp1
end
end
-get_roles_perm = function(self,roles)
- --for now we are using the file static
- --this will go through and search from the roles in sessionid to get the real
- --permission list
- local rolesfile = "/etc/acf/roles"
- f = fs.read_file_as_array(rolesfile)
- local temp = {}
- for k,v in pairs(roles) do
- for a,b in pairs(f) do
- match = "^" .. v
- c = string.match(b,match)
- if c then
- inval = string.match(b,"[,%w:]+$")
- temp[#temp +1] = inval
- end
+-- returns a table of the *.roles files
+-- startdir should be the app dir
+local get_roles_candidates = function (startdir)
+ local t = {}
+ local fh = io.popen('find ' .. startdir .. ' -name "*.roles"')
+ for x in fh:lines() do
+ t[#t + 1] = x
+ end
+ return t
+end
+
+-- Go through the roles files and determine the permissions for the specified roles
+get_roles_perm = function(startdir,roles)
+ permissions = {}
+
+ -- find all of the roles files and add in the master file
+ local rolesfiles = get_roles_candidates(startdir)
+ rolesfiles[#rolesfiles + 1] = "/etc/acf/roles"
+
+ local reverseroles = {}
+ for x,role in ipairs(roles) do
+ reverseroles[role] = {}
+ end
+ reverseroles["ALL"] = {} -- always include ALL role
+
+ for x,file in ipairs(rolesfiles) do
+ f = fs.read_file_as_array(file)
+ for y,line in pairs(f) do
+ if reverseroles[string.match(line,"^[%a]+")] then
+ temp = format.string_to_table(string.match(line,"[,%a:]+$"),",")
+ for z,perm in pairs(temp) do
+ local control,action = string.match(perm,"(%a+):(%a+)")
+ if control then
+ if nil == permissions[control] then
+ permissions[control] = {}
+ end
+ if action and nil == permissions[control][action] then
+ permissions[control][action] = {}
+ end
+ end
+ end
+ end
end
end
- temp1 = format.table_to_string(temp,",")
- --we now can return the first level of roles perms. What if a role is a member of a role...
- return temp1
+ return permissions
end
diff --git a/lib/session.lua b/lib/session.lua
index 18a0c7b..bd2bdf6 100644
--- a/lib/session.lua
+++ b/lib/session.lua
@@ -91,29 +91,30 @@ function serialize (name, value, saved )
return str
end
-save_session = function( sessionpath, session, sessiontable)
- local file = io.open(sessionpath .. "/session." .. session , "w")
- if file == nil then
- return nil
- end
-
- local id = sessiontable.id
+-- Save the session (unless all it contains is the id)
+-- return true or false for success
+save_session = function( sessionpath, sessiontable)
+ if nil == sessiontable or nil == sessiontable.id then return false end
- -- clear the id key
+ -- clear the id key, don't need to store that
+ local id = sessiontable.id
sessiontable.id = nil
- -- count the keys
- local count = 0
- for k,v in pairs (sessiontable) do
- count = count + 1
- end
+
-- If the table only has an "id" field, then don't save it
- if count > 1 and file then
+ if #sessiontable then
+ local file = io.open(sessionpath .. "/session." .. id , "w")
+ if file == nil then
+ sessiontable.id=id
+ return false
+ end
+
file:write ( "-- This is an ACF session table.\n")
file:write ( "\nlocal " )
file:write ( serialize("s", sessiontable) )
file:write ( "return s\n")
+ file:close()
end
- file:close()
+
sessiontable.id=id
return true
end
@@ -121,8 +122,9 @@ end
-- Loads a session
-- Returns a timestamp (when the session data was saved) and the session table.
--- We insert a "id" field from the "session"
+-- Insert the session into the "id" field
load_session = function ( sessionpath, session )
+ if type(session) ~= "string" then return nil, {} end
local s = {}
-- session can only have b64 characters in it
session = string.gsub ( session or "", "[^" .. b64 .. "]", "")
@@ -140,7 +142,8 @@ load_session = function ( sessionpath, session )
end
end
--- unlinks a session
+-- Unlinks a session (deletes the session file)
+-- return nil for failure, ?? for success
unlink_session = function (sessionpath, session)
if type(session) ~= "string" then return nil end
local s = string.gsub (session, "[^" .. b64 .. "]", "")
@@ -152,28 +155,6 @@ unlink_session = function (sessionpath, session)
return statos
end
---need to see if this is a "real"-user session or just a temp one.
-check_session = function (sessionpath, session )
- if session == nil then return "an unknown user" end
- local fullpath = sessionpath .. "/session." .. session
- if posix.stat(fullpath) == nil then return "an unknown user" end
- if type(session) ~= "string" then return nil end
- local s = string.gsub (session, "[^" .. b64 .. "]", "")
- if s ~= session then
- return nil
- end
- check_size = posix.stat(fullpath,"size")
- if check_size == 0 then
- return "an unknown user"
- else
- local c = dofile(fullpath).userinfo.userid
- local d = dofile(fullpath).userinfo.roles
- return c,d
- end
-
-
-end
-
-- Record an invalid login event
-- ID would typically be an ip address or username
-- the format is lockevent.id.datetime.processid
@@ -197,29 +178,23 @@ count_events = function (sessionpath, id_user, ipaddr)
local t = posix.glob(searchfor)
if t == nil or id_user == nil or ipaddr == nil then
- return false
- else
-
- local temp = {}
- for a,b in pairs(t) do
- if posix.stat(b,"mtime") > minutes_ago then
- temp[#temp + 1] = b end
- end
-
- local temp2 = {}
- for k,v in pairs(temp) do
- local c = string.match(v,id_user) or string.match(v,ipaddr)
- if c ~= nil then temp2[#temp2 + 1] = v end
- end
-
- if #temp2 > limit_count_events then
- return true
+ return false
else
- return false
- end
- end
-
+ local count = 0
+ for a,b in pairs(t) do
+ if posix.stat(b,"mtime") > minutes_ago then
+ if string.match(b,id_user) or string.match(b,ipaddr) then
+ count = count + 1
+ end
+ end
+ end
+ if count>limit_count_events then
+ return true
+ else
+ return false
+ end
end
+end
-- Clear events that are older than n minutes
expired_events = function (sessionpath)
diff --git a/roles b/roles
index 6784100..61349ef 100644
--- a/roles
+++ b/roles
@@ -1,5 +1,10 @@
-CREATE=password:administrator,password:status,interfaces:create,dhcp:createnet
-READ=welcome:read,interfaces:read,health:system,health:storage,health:proc,health:network,health:modules,opennhrp:status,opennhrp:logfile,tinydns:status,ipsectools:status,ipsectools:logfile,openntpd:status,openntpd:logfile,logfiles:status,logfiles:view,logfiles:download,syslog:status,lbu:status,dansguardian:basic,acfupdate:read,acfupdate:status,acfupdate:log,dhcp:home,dhcp:viewleases,dhcp:viewconfig,openvpn:status,openvpn:statusinfo,openvpn:logfile,shorewall:status,shorewall:logfile,snort:status,squid:basic,quagga:status,quagga:logfile,password:editme,fetchmail:status,dhcp:status,dnscache:status,dnscache:logfile,gnats:status,gnats:query,gnats:queryresult,gnats:summary,gnats:report,chrony:status,chrony:logfile,
-UPDATE=skins:update,syslog:config,syslog:expert,acfupdate:update,acfupdate:diff,skins:read,interfaces:update,interfaces:config,lbu:config,lbu:commit,lbu:expert,dansguardian:general,dansguardian:advanced,dansguardian:plain,dansguardian:edit,dansguardian:category,dhcp:dep,dhcp:help,dhcp:settings,dhcp:editnet,dhcp:editspc,fetchmail:expert,ipsectools:expert,opennhrp:expert,openntpd:expert,openntpd:config,openvpn:serverconfig,openvpn:clientconfig,openvpn:peminfo,openvpn:unknownconfig,quagga:expert,shorewall:editrecords,shorewall:config,shorewall:check,shorewall:expert,shorewall:edit,snort:expert,squid:dep,squid:authentication,squid:advanced,squid:digest,squid:saccess,tinydns:expert,dnscache:expert,chrony:expert,
+ALL=welcome:read,logon:logon,logon:logout,logon:status
+CREATE=password:administrator,password:status
+READ=password:editme,password:save
+NONE=roles:read,roles:getlist
+
+CREATE=interfaces:create,dhcp:createnet
+READ=interfaces:read,health:system,health:storage,health:proc,health:network,health:modules,opennhrp:status,opennhrp:logfile,tinydns:status,ipsectools:status,ipsectools:logfile,openntpd:status,openntpd:logfile,logfiles:status,logfiles:view,logfiles:download,syslog:status,lbu:status,acfupdate:read,acfupdate:status,acfupdate:log,dhcp:home,dhcp:viewleases,dhcp:viewconfig,openvpn:status,openvpn:statusinfo,openvpn:logfile,shorewall:status,shorewall:logfile,snort:status,squid:basic,quagga:status,quagga:logfile,fetchmail:status,dhcp:status
+UPDATE=skins:update,syslog:config,syslog:expert,acfupdate:update,acfupdate:diff,skins:read,interfaces:update,lbu:config,lbu:commit,lbu:expert,dansguardian:general,dansguardian:advanced,dansguardian:plain,dansguardian:edit,dansguardian:category,dhcp:dep,dhcp:help,dhcp:settings,dhcp:editnet,dhcp:editspc,fetchmail:expert,ipsectools:expert,opennhrp:expert,openntpd:expert,openntpd:config,openvpn:serverconfig,openvpn:clientconfig,openvpn:peminfo,openvpn:unknownconfig,quagga:expert,shorewall:editrecords,shorewall:config,shorewall:check,shorewall:expert,shorewall:edit,snort:expert,squid:dep,squid:authentication,squid:advanced,squid:digest,squid:saccess,tinydns:expert,apk:loaded,apk:available,apk:delete,apk:install
DELETE=interfaces:delete,logfiles:delete,dhcp:delnet
-ALL=welcome:read,health:system,lbu:status,gnats:status,gnats:query,gnats:queryresult,gnats:summary,gnats:report
+ALL=health:system,lbu:status
diff --git a/www/cgi-bin/mvc.lua b/www/cgi-bin/mvc.lua
index da80184..2b7c8b4 100755
--- a/www/cgi-bin/mvc.lua
+++ b/www/cgi-bin/mvc.lua
@@ -97,37 +97,86 @@ new = function (self, modname)
end
-- This is a sample front controller/dispatch.
-dispatch = function (self, prefix, userctlr, action)
+dispatch = function (self, userprefix, userctlr, useraction)
local controller
local success, err = xpcall ( function ()
- if prefix == nil then
+ if userprefix == nil then
self.conf.prefix, self.conf.controller, self.conf.action =
parse_path_info(ENV["PATH_INFO"])
else
- self.conf.prefix = prefix
+ self.conf.prefix = userprefix
self.conf.controller = userctlr or ""
- self.conf.action = action or ""
+ self.conf.action = useraction or ""
end
- -- If they didn't provide a controller, and a default was specified
- -- use it
- if self.conf.controller == "" and self.conf.default_controller then
+ -- Find the proper controller/action combo
+ local origconf = {controller = self.conf.controller, action = self.conf.action}
+ local controller = nil
+ local action = ""
+ self.conf.default_controller = self.conf.default_controller or ""
+ if "" == self.conf.controller then
self.conf.controller = self.conf.default_controller
+ self.conf.action = ""
end
+ while "" ~= self.conf.controller do
+ -- We now know the controller / action combo, check if we're allowed to do it
+ local perm = true
+ if type(self.worker.mvc.check_permission) == "function" then
+ perm = self.worker.mvc.check_permission(self, self.conf.controller)
+ end
- controller = self:new(self.conf.prefix .. self.conf.controller)
-
- local action = controller.conf.action
+ if perm then
+ controller = self:new(self.conf.prefix .. self.conf.controller)
+ end
+ if controller then
+ controller.conf.default_action = controller.conf.default_action or ""
+ action = controller.conf.action or ""
+ if "" == action then
+ action = controller.conf.default_action
+ end
+ while "" ~= action do
+ local perm = true
+ if type(controller.worker.mvc.check_permission) == "function" then
+ perm = controller.worker.mvc.check_permission(controller, self.conf.controller, action)
+ end
+ -- Because of the inheritance, normally the
+ -- controller.worker.action will flow up, so that all children have
+ -- actions of all parents. We use rawget to make sure that only
+ -- controller defined actions are used on dispatch
+ if perm and (type(rawget(controller.worker, action)) == "function") then
+ -- We have a valid and permissible controller / action
+ self.conf.action = action
+ controller.conf.action = action
+ break
+ end
+ if action ~= controller.conf.default_action then
+ action = controller.conf.default_action
+ else
+ action = ""
+ end
+ end
+ if "" ~= action then break end
+ end
+ controller = nil
+ self.conf.action = ""
+ if self.conf.controller ~= self.conf.default_controller then
+ self.conf.controller = self.conf.default_controller
+ else
+ self.conf.controller = ""
+ end
+ end
- -- Because of the inheritance, normally the
- -- controller.worker.action will flow up, so that all children have
- -- actions of all parents. We sue rawget to make sure that only
- -- controller defined actions are used on dispatch
-- If the controller or action are missing, raise an error
- if ( type(rawget(controller.worker, action)) ~= "function") then
- self.conf.type = "dispatch"
- error (self.conf)
+ if nil == controller then
+ origconf.type = "dispatch"
+ error (origconf)
+ end
+
+ -- If we have different controller / action, redirect
+ if self.conf.controller ~= origconf.controller or self.conf.action ~= origconf.action then
+ self.conf.type = "redir"
+ error(self.conf)
end
-- run the (first found) pre_exec code, starting at the controller