summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/acf-util/logon-model.lua22
-rwxr-xr-xapp/acf-util/password-controller.lua132
-rwxr-xr-xapp/acf-util/password-model.lua112
-rwxr-xr-xapp/acf-util/password-status-html.lsp3
-rw-r--r--app/acf-util/roles-model.lua4
-rw-r--r--lib/Makefile1
-rw-r--r--lib/authenticator-plaintext.lua327
-rw-r--r--lib/authenticator.lua293
8 files changed, 390 insertions, 504 deletions
diff --git a/app/acf-util/logon-model.lua b/app/acf-util/logon-model.lua
index 3644a09..b817cf9 100644
--- a/app/acf-util/logon-model.lua
+++ b/app/acf-util/logon-model.lua
@@ -6,18 +6,7 @@ require ("session")
require ("html")
require ("fs")
require ("roles")
-
---varibles for time in case of logons,expired,lockouts
-
--- load an authenticator
--- FIXME: use an "always true" as default?
-
-local auth
-if authenticator then
- auth = require ("authenticator-" .. conf.authenticator)
-else
- auth = require ("authenticator-plaintext")
-end
+require ("authenticator")
-- Logoff the user by deleting session data
logoff = function (sessiondir, sessiondata)
@@ -42,7 +31,7 @@ logon = function (self, userid, password, ip_addr, sessiondir, sessiondata)
end
if false == countevent and userid and password then
- if auth.authenticate (self, userid, password) then
+ if authenticator.authenticate (self, userid, password) 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)
@@ -54,8 +43,11 @@ logon = function (self, userid, password, ip_addr, sessiondir, sessiondata)
end
--]]
sessiondata.id = session.random_hash(512)
- local t = auth.get_userinfo (self, userid)
- sessiondata.userinfo = t or {}
+ local t = authenticator.get_userinfo (self, userid)
+ sessiondata.userinfo = {}
+ for name,value in pairs(t.value) do
+ sessiondata.userinfo[name] = value.value
+ end
return cfe({ type="boolean", value=true, label="Logon Success" })
else
-- We have a bad login, log the event
diff --git a/app/acf-util/password-controller.lua b/app/acf-util/password-controller.lua
index 20f04ef..bea4480 100755
--- a/app/acf-util/password-controller.lua
+++ b/app/acf-util/password-controller.lua
@@ -8,97 +8,59 @@ function status(self)
end
function editme(self)
- local output = self.model.read_user(self, self.sessiondata.userinfo.userid)
-
- if clientdata.Save then
- -- just to make sure can't modify any other user from this action
- self.clientdata.userid = self.sessiondata.userinfo.userid
-
- -- As a special case for update_user, settings that don't change are nil
- self.clientdata.roles = nil
- output.value.roles.value = nil
- -- if password is blank, don't update it or require it
- if not self.clientdata.password or self.clientdata.password == "" then
- self.clientdata.password = nil
- output.value.password.value = nil
- end
- if not self.clientdata.password_confirm or self.clientdata.password_confirm == "" then
- self.clientdata.password_confirm = nil
- output.value.password_confirm.value = nil
- end
-
- controllerfunctions.handle_clientdata(output, clientdata)
-
- -- Update userinfo
- output = self.model.update_user(self, output)
- if not output.errtxt then
- output.descr = "Saved user"
- end
- output = self:redirect_to_referrer(output)
- else
- output = self:redirect_to_referrer() or output
- end
-
- -- Don't allow changing of roles for yourself
- output.value.roles = nil
-
- output.type = "form"
- output.label = "Edit My Settings"
- output.option = "Save"
- return output
+ -- just to make sure can't modify any other user from this action
+ self.clientdata.userid = self.sessiondata.userinfo.userid
+ return controllerfunctions.handle_form(self, function()
+ local value = self.model.read_user(self, self.sessiondata.userinfo.userid)
+ -- We don't allow a user to modify his own roles or dnsfiles
+ value.value.roles = nil
+ value.value.dnsfiles = nil
+ return value
+ end, function(value)
+ -- If password and password_confirm are blank, don't set them
+ local pw, pwc
+ if value.value.password.value == "" and value.value.password_confirm.value == "" then
+ pw = value.value.password
+ pwc = value.value.password_confirm
+ value.value.password = nil
+ value.value.password_confirm = nil
+ end
+ value = self.model.update_user(self, value)
+ if pw then
+ value.value.password = pw
+ value.value.password_confirm = pwc
+ end
+ return value
+ end, self.clientdata, "Save", "Edit My Settings", "Saved user")
end
function edituser(self)
- local output = self.model.read_user(self, self.clientdata.userid)
- if self.clientdata.Save then
- -- As a special case for update_user, settings that don't change are nil
- -- if password is blank, don't update it or require it
- if not self.clientdata.password or self.clientdata.password == "" then
- self.clientdata.password = nil
- output.value.password.value = nil
- end
- if not self.clientdata.password_confirm or self.clientdata.password_confirm == "" then
- self.clientdata.password_confirm = nil
- output.value.password_confirm.value = nil
- end
-
- controllerfunctions.handle_clientdata(output, clientdata)
-
- -- Update userinfo
- output = self.model.update_user(self, output)
- if not output.errtxt then
- redirect(self, "status")
- end
- output = self:redirect_to_referrer(output)
- else
- output = self:redirect_to_referrer() or output
- end
-
- output.type = "form"
- output.label = "Edit User Settings"
- output.option = "Save"
- return output
+ return controllerfunctions.handle_form(self, function()
+ return self.model.read_user(self, self.clientdata.userid)
+ end, function(value)
+ -- If password and password_confirm are blank, don't set them
+ local pw, pwc
+ if value.value.password.value == "" and value.value.password_confirm.value == "" then
+ pw = value.value.password
+ pwc = value.value.password_confirm
+ value.value.password = nil
+ value.value.password_confirm = nil
+ end
+ value = self.model.update_user(self, value)
+ if pw then
+ value.value.password = pw
+ value.value.password_confirm = pwc
+ end
+ return value
+ end, self.clientdata, "Save", "Edit User Settings", "Saved user")
end
function newuser(self)
- local output = self.model.read_user(self)
- if self.clientdata.Save then
- controllerfunctions.handle_clientdata(output, clientdata)
-
- -- Update userinfo
- output = self.model.create_user(self, output)
- if not output.errtxt then
- redirect(self, "status")
- end
- output = self:redirect_to_referrer(output)
- else
- output = self:redirect_to_referrer() or output
- end
-
- output.type = "form"
- output.label = "New User Settings"
- output.option = "Save"
- return output
+ return controllerfunctions.handle_form(self, function()
+ return self.model.read_user(self)
+ end, function(value)
+ return self.model.create_user(self, value)
+ end, self.clientdata, "Save", "New User Settings", "Saved user", "status")
end
function deleteuser(self)
diff --git a/app/acf-util/password-model.lua b/app/acf-util/password-model.lua
index 1e78e5d..87c2e6f 100755
--- a/app/acf-util/password-model.lua
+++ b/app/acf-util/password-model.lua
@@ -1,125 +1,33 @@
module(..., package.seeall)
-local auth=require("authenticator-plaintext")
+require("authenticator")
function create_user(self, userdata)
- return update_user(self, userdata, true)
+ return authenticator.new_settings(self, userdata)
end
function read_user(self, user)
- local config = {}
- local errtxt
-
- -- Read the user data
- local userinfo
- if user and (#user > 0) then
- userinfo = auth.get_userinfo(self,user)
- if not userinfo then
- errtxt = "User does not exist"
- end
- end
- userinfo = userinfo or {}
-
- config.userid = cfe({
- label="User id",
- value=(userinfo.userid or user or ""),
- errtxt = errtxt
- })
- config.username = cfe({
- label="Real name",
- value=(userinfo.username or ""),
- })
- config.roles = cfe({
- label="Roles",
- value=(userinfo.roles or {}),
- type="multi",
- option=auth.list_roles(),
- })
- config.password = cfe({
- label="Password",
- })
- config.password_confirm = cfe({
- label="Password (confirm)",
- })
-
- return cfe({ type="group", value=config, errtxt = errtxt, label="User Config" })
+ return authenticator.get_userinfo(self, user)
end
-function update_user(self, userdata, newuser)
- local result
- local errormessage = {}
-
- -- Try to write new or update existing data
- if newuser == true then
- result, errormessage = auth.new_settings(self, userdata.value.userid.value, userdata.value.username.value, userdata.value.password.value, userdata.value.password_confirm.value, userdata.value.roles.value)
- if result == false then
- userdata.errtxt = "Failed to create new user"
- end
- else
- -- As a special case, settings that don't change are nil
- result, errormessage = auth.change_settings(self, userdata.value.userid.value, userdata.value.username.value, userdata.value.password.value, userdata.value.password_confirm.value, userdata.value.roles.value)
- if result == false then
- userdata.errtxt = "Failed to save changes"
- end
- -- We can't return any nil values, so set then
- local olduserdata = read_user(self, userdata.value.userid.value)
- for name,value in pairs(userdata.value) do
- if value.value == nil then
- value.value = olduserdata.value[name].value
- end
- end
- end
-
- userdata.value.password.value = ""
- userdata.value.password_confirm.value = ""
-
- if result == false then
- -- now, copy in the errors
- for name,value in pairs(userdata.value) do
- value.errtxt = errormessage[name]
- end
- end
-
- return userdata
+function update_user(self, userdata)
+ return authenticator.change_settings(self, userdata)
end
function get_users(self)
--List all users and their userinfo
local users = {}
- local userlist = auth.list_users(self)
+ local userlist = authenticator.list_users(self)
for x,user in pairs(userlist) do
- local userinfo = auth.get_userinfo(self,user)
- users[user] = cfe({
- type="group",
- label=user,
- value={ userid=cfe ({
- label="User ID",
- value=userinfo.userid,
- }),
- username=cfe ({
- label="Real name",
- value=userinfo.username,
- }),
- roles=cfe ({
- label="Roles",
- value=userinfo.roles,
- option=auth.list_roles(),
- type="multi",
- }),
- },
-
- })
+ users[user] = read_user(self, user)
+ users[user].value.password = nil
+ users[user].value.password_confirm = nil
end
return cfe({ type="group", value=users, label="User Configs" })
end
function delete_user(self, userid)
- local result, errmessages = auth.delete_user(self, userid)
- local value
- if result then value = "User Deleted" else value = "Failed to Delete User" end
- local errtxt
- if #errmessages > 0 then errtxt = errmessages:concat("\n") end
- return cfe({ value=value, errtxt=errtxt, label="Delete User Result" })
+ return authenticator.delete_user(self, userid)
end
diff --git a/app/acf-util/password-status-html.lsp b/app/acf-util/password-status-html.lsp
index c16e0d6..8091316 100755
--- a/app/acf-util/password-status-html.lsp
+++ b/app/acf-util/password-status-html.lsp
@@ -30,6 +30,9 @@ io.write("</span>")
<TD STYLE='border:none;'><B><?= user.value.roles.label ?></B></TD>
<TD STYLE='border:none;'><?= table.concat(user.value.roles.value, " / ") ?></TD>
</TR><TR>
+ <TD STYLE='border:none;'><B><?= user.value.dnsfiles.label ?></B></TD>
+ <TD STYLE='border:none;'><?= table.concat(user.value.dnsfiles.value, "<br>") ?></TD>
+ </TR><TR>
<TD STYLE='border:none;'><B>Option</B></TD>
<TD STYLE='border:none;'>
[<A HREF='edituser?userid=<?= name ?>'>Edit this account</A>]
diff --git a/app/acf-util/roles-model.lua b/app/acf-util/roles-model.lua
index b2db9db..f064536 100644
--- a/app/acf-util/roles-model.lua
+++ b/app/acf-util/roles-model.lua
@@ -2,7 +2,7 @@
module (..., package.seeall)
require("modelfunctions")
-auth = require("authenticator-plaintext")
+require("authenticator")
require("roles")
local get_all_permissions = function(self)
@@ -26,7 +26,7 @@ end
-- Return roles/permissions for specified user
get_user_roles = function(self, userid)
- rls = cfe({ type="list", value=auth.get_userinfo_roles(self, userid), label="Roles" })
+ rls = cfe({ type="list", value=authenticator.get_userinfo_roles(self, userid).value, label="Roles" })
permissions = cfe({ type="table", value=roles.get_roles_perm(self.conf.appdir, rls.value), label="Permissions" })
return cfe({ type="group", value={roles=rls, permissions=permissions} })
end
diff --git a/lib/Makefile b/lib/Makefile
index c064fe4..23a1a31 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -13,6 +13,7 @@ LIB_DIST=fs.lua\
split.lua\
validator.lua\
web_elements.lua\
+ authenticator.lua\
authenticator-plaintext.lua\
daemoncontrol.lua\
getopts.lua\
diff --git a/lib/authenticator-plaintext.lua b/lib/authenticator-plaintext.lua
index f7bdd1a..e2262b3 100644
--- a/lib/authenticator-plaintext.lua
+++ b/lib/authenticator-plaintext.lua
@@ -5,41 +5,36 @@
The password file is in the format:
-userid:password:username:role1[,role2...]
+userid:password:username:role1[,role2...]:dnsfile1[,dnsfile2...]
]]--
module (..., package.seeall)
-local sess = require ("session")
-require("roles")
-
-local pvt={}
-
-pvt.parse_authfile = function(filename)
+load_database = function(self)
local row = {}
-- open our password file
- local f = io.open (filename)
+ local passwd_path = self.conf.confdir .. "/passwd"
+ local f = io.open(passwd_path)
if f then
local m = (f:read("*all") or "" ).. "\n"
f:close()
- for l in string.gmatch(m, "(%C*)\n") do
- local userid, password, username, roles =
- string.match(l, "([^:]*):([^:]*):([^:]*):(.*)")
- local r = {}
- roles=roles or ""
- for x in string.gmatch(roles, "([^,][%w_]+),?") do
- table.insert (r, x )
+ for l in string.gmatch(m, "([^\n]+)\n?") do
+ local fields = {}
+ for x in string.gmatch(l, "([^:]*):?") do
+ fields[#fields + 1] = x
+ end
+ if fields[1] and fields[1] ~= "" then
+ local a = {}
+ a.userid = fields[1] or ""
+ a.password = fields[2] or ""
+ a.username = fields[3] or ""
+ a.roles = fields[4] or ""
+ a.dnsfiles = fields[5] or ""
+ table.insert (row, a)
end
-
- local a = {}
- a.userid = userid
- a.password = password
- a.username = username
- a.roles = r
- table.insert (row, a)
end
return row
else
@@ -47,295 +42,27 @@ pvt.parse_authfile = function(filename)
end
end
-pvt.get_id = function(userid, authstruct)
- if authstruct ~= nil then
- for x = 1,#authstruct do
- if authstruct[x].userid == userid then
- return authstruct[x]
- end
- end
- end
- return nil
-end
-
-pvt.weak_password = function(password)
- -- If password is too short, return false
- if (#password < 4) then
- return true, "Password is too short!"
- end
- if (tonumber(password)) then
- return true, "Password can't contain only numbers!"
- end
-
- return false
-end
-
-pvt.availablefields = function (field)
- -- This is a list of fileds in the /passwd file that we are allowed to use.
- -- Could be used to check that right variable-name is used.
- local availablefileds = {
- ['userid']=true,
- ['password']=true,
- ['username']=true,
- ['roles']=true,
- }
- return availablefileds[field]
-end
-
--- validate the settings (ignore password if it's nil)
-local validate_settings = function (self, userid, username, password, password_confirm, roles)
- local errormessage = {}
-
- -- Set errormessages when entering invalid values
- if (#userid == 0) then errormessage.userid = "You need to enter a valid userid!" end
- if string.find(userid, "[^%w_]") then errormessage.userid = "Userid can only contain letters, numbers, and '_'" end
- if string.find(username, "%p") then errormessage.username = "Real name cannot contain punctuation" end
- if password then
- if (#password == 0) then
- errormessage.password = "Password cannot be blank!"
- elseif (password ~= password_confirm) then
- errormessage.password_confirm = "You entered wrong password/confirmation"
- else
- local weak_password_result, weak_password_errormessage = pvt.weak_password(password)
- if (weak_password_result) then errormessage.password = weak_password_errormessage end
- end
- end
- local reverseroles = {}
- for x,role in pairs(list_roles(self)) do
- reverseroles[role] = x
- end
- for x,role in pairs(roles) do
- if reverseroles[role] == nil then
- errormessage.roles = "Invalid role"
- break
- end
- end
-
- -- Return false if any errormessages are set
- for k,v in pairs(errormessage) do
- return false, errormessage
- end
-
- return true, errormessage
-end
-
---- public methods
-
--- This function returns true or false, and
--- if false: the reason for failure
-authenticate = function ( self, userid, password )
- password = password or ""
- userid = userid or ""
-
- local t = pvt.parse_authfile(self.conf.confdir .. "/passwd")
-
- if t == false then
- return false, "password file is missing"
- end
-
- if userid ~= nil then
- local id = pvt.get_id (userid, t)
- if id == false or id == nil then
- return false, "Userid not found"
- end
- if id.password ~= fs.md5sum_string(password) then
- return false, "Invalid password"
- end
- else
- return false
- end
+write_entry = function(self, entry)
+ delete_entry(self, entry.userid)
+ -- Set path to passwordfile
+ local passwd_path = self.conf.confdir .. "/passwd"
+ -- Write the newline into the file
+ fs.write_line_file(passwd_path, (entry.userid or "") .. ":" .. (entry.password or "") .. ":" .. (entry.username or "") .. ":" .. (entry.roles or "") .. ":" .. (entry.dnsfiles or "") )
return true
end
--- This function returns the username and roles
--- or false on an error
-get_userinfo = function ( self, userid )
- local t = pvt.parse_authfile(self.conf.confdir .. "/passwd")
- if t == false then
- return nil
- else
- return pvt.get_id (userid, t)
- end
-end
-
-get_userinfo_roles = function (self, userid)
- local t = pvt.parse_authfile(self.conf.confdir .. "/passwd")
- if t == false then
- return nil
- else
- temp = pvt.get_id (userid, t)
- return temp.roles
- end
-end
-
-list_users = function (self)
- local output = {}
- local t = pvt.parse_authfile(self.conf.confdir .. "/passwd")
- if t == false then
- return nil
- else
- for k,v in pairs(t) do
- table.insert(output,v.userid)
- end
- return output
-
- end
-end
-
-list_roles = function (self)
- -- Get list of available roles (everything except ALL)
- local avail_roles = roles.list_all_roles()
- for x,role in ipairs(avail_roles) do
- if role=="ALL" then
- table.remove(avail_roles,x)
- break
- end
- end
- return avail_roles
-end
-
-change_setting = function (self, userid, parameter, value)
- local result = true
- local errormessage = {}
-
- -- Get the current user info
- local userinfo = get_userinfo(self, userid)
- if userinfo == nil then
- errormessage.userid = "This userid does not exist!"
- result = false
- end
-
- -- Check if user entered available commands
- if not (userid) or not (parameter) or not (pvt.availablefields(parameter)) or not (value) then
- errormessage.userid = "You need to enter valid userid, parameter and value!"
- result = false
- end
-
- -- Check if userid already used
- if (parameter == "userid") and (userid ~= value) then
- for k,v in pairs(list_users(self)) do
- if (v == value) then
- errormessage.userid = "This userid already exists!"
- result = false
- end
- end
- end
-
- if result == true then
- -- Validate parameter
- userinfo[parameter] = value
- local password, password_confirm
- if (parameter == "password") then
- userinfo.password = fs.md5sum_string(value)
- password = value
- password_confirm = value
- end
- result, errormessage = validate_settings(self, username.userid, userinfo.username, password, password_confirm, userinfo.roles)
- end
-
- -- Write the updated user
- if (result == true) then
- delete_user(self, userid)
-
- -- Set path to passwordfile
- local passwd_path = self.conf.confdir .. "/passwd"
- -- Write the newline into the file
- fs.write_line_file(passwd_path, userinfo.userid .. ":" .. userinfo.password .. ":" .. userinfo.username .. ":" .. table.concat(userinfo.roles,",") )
- end
-
- return result, errormessage
-end
-
--- For an existing user, change the settings that are non-nil
-change_settings = function (self, userid, username, password, password_confirm, roles)
- local result = true
- local errormessage = {}
-
- -- Get the current user info
- local userinfo = get_userinfo(self, userid)
- if userinfo == nil then
- errormessage.userid = "This userid does not exist!"
- result = false
- end
-
- local change = username or password or password_confirm or roles
- if change then
- -- Validate the inputs
- if (result == true) then
- -- Use the current settings if new ones are nil, except for password
- result, errormessage = validate_settings(self, userid, username or userinfo.username, password, password_confirm, roles or userinfo.roles)
- end
-
- -- Update all the fields
- if (result == true) then
- userinfo.username = username or userinfo.username
- if password then
- userinfo.password = fs.md5sum_string(password)
- end
- userinfo.roles = roles or userinfo.roles
-
- -- Write the updated user
- delete_user(self, userid)
-
- -- Set path to passwordfile
- local passwd_path = self.conf.confdir .. "/passwd"
- -- Write the newline into the file
- fs.write_line_file(passwd_path, userid .. ":" .. userinfo.password .. ":" .. userinfo.username .. ":" .. table.concat(userinfo.roles,",") )
- end
- end
-
- return result, errormessage
-end
-
-new_settings = function (self, userid, username, password, password_confirm, roles)
- local result = true
- local errormessage = {}
- -- make sure to check all fields
- userid = userid or ""
- username = username or ""
- password = password or ""
- password_confirm = password_confirm or ""
- roles = roles or {}
-
- -- Check if userid already used
- for k,v in pairs(list_users(self)) do
- if (v == userid) then
- errormessage.userid = "This userid already exists!"
- result = false
- end
- end
-
- -- validate the settings
- if (result == true) then
- result, errormessage = validate_settings(self, userid, username, password, password_confirm, roles)
- end
-
- -- write the new user
- if (result == true) then
- -- Set path to passwordfile
- local passwd_path = self.conf.confdir .. "/passwd"
-
- -- Write the newline into the file
- fs.write_line_file(passwd_path, userid .. ":" .. fs.md5sum_string(password) .. ":" .. username .. ":" .. table.concat(roles,",") )
- end
-
- return result, errormessage
-end
-
-delete_user = function (self, userid)
+delete_entry = function (self, userid)
local result = false
- local errormessage = {userid="User not found"}
-
+
local passwd_path = self.conf.confdir .. "/passwd"
local passwdfilecontent = fs.read_file_as_array(passwd_path)
local output = {}
for k,v in pairs(passwdfilecontent) do
- if not ( string.match(v, "^".. userid .. ":") ) then
+ if not ( string.match(v, "^".. userid .. ":") ) and not string.match(v, "^%s*$") then
table.insert(output, v)
else
result = true
- errormessage = {}
end
end
@@ -344,5 +71,5 @@ delete_user = function (self, userid)
fs.write_file(passwd_path, table.concat(output,"\n"))
end
- return result, errormessage
+ return result
end
diff --git a/lib/authenticator.lua b/lib/authenticator.lua
new file mode 100644
index 0000000..e6310ec
--- /dev/null
+++ b/lib/authenticator.lua
@@ -0,0 +1,293 @@
+-- ACF Authenticator - does validation and loads sub-authenticator to read/write database
+module (..., package.seeall)
+
+require("modelfunctions")
+require("fs")
+
+-- This will be the sub-authenticator
+local auth
+-- This will hold the auth structure from the database
+local authstruct
+-- This is a list of fields in the database that we are allowed to use.
+-- Could be used to check that right variable-name is used.
+local availablefields = {
+ ['userid']=true,
+ ['password']=true,
+ ['username']=true,
+ ['roles']=true,
+ ['dnsfiles']=true,
+ }
+
+
+local load_auth = function(self)
+ -- For now, just loads the plaintext version
+ auth = auth or require("authenticator-plaintext")
+end
+
+local load_database = function(self)
+ load_auth(self)
+ authstruct = authstruct or auth.load_database(self)
+end
+
+local get_id = function(userid)
+ if authstruct ~= nil then
+ for x = 1,#authstruct do
+ if authstruct[x].userid == userid then
+ return authstruct[x]
+ end
+ end
+ end
+ return nil
+end
+
+local weak_password = function(password)
+ -- If password is too short, return false
+ if (#password < 4) then
+ return true, "Password is too short!"
+ end
+ if (tonumber(password)) then
+ return true, "Password can't contain only numbers!"
+ end
+
+ return false, nil
+end
+
+local write_settings = function(self, settings, id)
+ load_auth()
+ id = id or {}
+ -- Password, password_confirm, roles, dnsfiles are allowed to not exist, just leave the same
+ id.userid = settings.value.userid.value
+ id.username = settings.value.username.value
+ if settings.value.password then id.password = fs.md5sum_string(settings.value.password.value) end
+ if settings.value.roles then id.roles = table.concat(settings.value.roles.value, ",") end
+ if settings.value.dnsfiles then id.dnsfiles = table.concat(settings.value.dnsfiles.value, ",") end
+
+ return auth.write_entry(self, id)
+end
+
+-- validate the settings (ignore password if it's nil)
+local validate_settings = function(settings)
+ -- Password, password_confirm, roles, dnsfiles are allowed to not exist, just leave the same
+ -- Set errtxt when entering invalid values
+ if (#settings.value.userid.value == 0) then settings.value.userid.errtxt = "You need to enter a valid userid!" end
+ if string.find(settings.value.userid.value, "[^%w_]") then settings.value.userid.errtxt = "Can only contain letters, numbers, and '_'" end
+ if string.find(settings.value.username.value, "%p") then settings.value.username.value = "Cannot contain punctuation" end
+ if settings.value.password then
+ if (#settings.value.password.value == 0) then
+ settings.value.password.errtxt = "Password cannot be blank!"
+ elseif (not settings.value.password_confirm) or (settings.value.password.value ~= settings.value.password_confirm.value) then
+ settings.value.password.errtxt = "You entered wrong password/confirmation"
+ else
+ local weak_password_result, weak_password_errormessage = weak_password(settings.value.password.value)
+ if (weak_password_result) then settings.value.password.errtxt = weak_password_errormessage end
+ end
+ end
+ if settings.value.roles then modelfunctions.validatemulti(settings.value.roles) end
+ if settings.value.dnsfiles then modelfunctions.validatemulti(settings.value.dnsfiles) end
+
+ -- Return false if any errormessages are set
+ for name,value in pairs(settings.value) do
+ if value.errtxt then
+ return false, settings
+ end
+ end
+
+ return true, settings
+end
+
+--- public methods
+
+-- This function returns true or false, and
+-- if false: the reason for failure
+authenticate = function(self, userid, password)
+ local errtxt
+
+ if not userid or not password then
+ errtxt = "Invalid parameter"
+ else
+ load_database(self)
+
+ if authstruct == false then
+ errtxt = "Could not load authentication database"
+ else
+ local id = get_id(userid)
+ if not id then
+ errtxt = "Userid not found"
+ elseif id.password ~= fs.md5sum_string(password) then
+ errtxt = "Invalid password"
+ end
+ end
+ end
+
+ return (errtxt == nil), errtxt
+end
+
+-- This function returns the username, roles, ...
+get_userinfo = function(self, userid)
+ load_database(self)
+ local id = get_id(userid)
+ local user = cfe({ value=userid, label="User id" })
+ local username = cfe({ label="Real name" })
+ if id then
+ username.value = id.username
+ elseif userid then
+ user.errtxt = "User does not exist"
+ end
+ local password = cfe({ label="Password" })
+ local password_confirm = cfe({ label="Password (confirm)" })
+ local roles = get_userinfo_roles(self, userid)
+ local dnsfiles = get_userinfo_dnsfiles(self, userid)
+
+ return cfe({ type="group", value={ userid=user, username=username, password=password, password_confirm=password_confirm, roles=roles, dnsfiles=dnsfiles }, label="User Config" })
+end
+
+get_userinfo_roles = function(self, userid)
+ load_database(self)
+ local id = get_id(userid)
+ local roles = cfe({ type="multi", value={}, label="Roles", option={} })
+ if id then
+ for x in string.gmatch(id.roles or "", "([^,]+),?") do
+ roles.value[#roles.value + 1] = x
+ end
+ elseif userid then
+ roles.errtxt = "Could not load roles"
+ end
+ local rol = require("roles")
+ if rol then
+ local avail_roles = rol.list_all_roles()
+ for x,role in ipairs(avail_roles) do
+ if role=="ALL" then
+ table.remove(avail_roles,x)
+ break
+ end
+ end
+ roles.option = avail_roles
+ end
+ return roles
+end
+
+get_userinfo_dnsfiles = function(self, userid)
+ load_database(self)
+ local id = get_id(userid)
+ local dnsfiles = cfe({ type="multi", value={}, label="DNS Files", option={} })
+ if id then
+ for x in string.gmatch(id.dnsfiles or "", "([^,]+),?") do
+ dnsfiles.value[#dnsfiles.value + 1] = x
+ end
+ elseif userid then
+ dnsfiles.errtxt = "Could not load DNS files"
+ end
+ local dns = self:new("tinydns/tinydns")
+ if dns then
+ local avail_files = dns.model.getfilelist()
+ dnsfiles.option = avail_files.value
+ dns:destroy()
+ end
+ return dnsfiles
+end
+
+list_users = function (self)
+ load_database(self)
+ local output = {}
+ if authstruct then
+ for k,v in pairs(authstruct) do
+ table.insert(output,v.userid)
+ end
+ end
+ return output
+end
+
+-- UNTESTED
+-- This function will change one user setting by name
+-- Cannot be used for password or userid
+change_setting = function (self, userid, parameter, value)
+ local success = false
+ local cmdresult = "Failed to change setting"
+ local errtxt
+
+ -- Get the current user info
+ local userinfo = get_userinfo(self, userid)
+ if not userinfo then
+ errtxt = "This userid does not exist"
+ end
+
+ -- Check if user entered available commands
+ if not value then
+ errtxt = "Invalid value"
+ elseif not (pvt.availablefields(parameter)) then
+ errtxt = "Invalid parameter"
+ elseif parameter == "userid" or parameter == "password" then
+ errtxt = "Cannot change "..parameter.." with this function"
+ else
+ userinfo.value[parameter].value = value
+ userinfo.value.password = nil
+ userinfo.value.password_confirm = nil
+ if not validate_settings(userinfo) then
+ errtxt = userinfo.value[parameter].errtxt
+ else
+ success = write_settings(settings)
+ end
+ end
+
+ if success then cmdresult = "Changed setting" end
+
+ return cfe({ value=cmdresult, label="Change setting result", errtxt=errtxt })
+end
+
+-- For an existing user, change the settings that are non-nil
+change_settings = function (self, settings)
+ local success, settings = validate_settings(settings)
+
+ -- Get the current user info
+ local id
+ if success then
+ load_database(self)
+ id = get_id(settings.value.userid.value)
+ if not id then
+ settings.value.userid.errtxt = "This userid does not exist!"
+ success = false
+ end
+ end
+
+ if success then
+ success = write_settings(self, settings, id)
+ end
+
+ if not success then
+ settings.errtxt = "Failed to save settings"
+ end
+
+ return settings
+end
+
+new_settings = function (self, settings)
+ local success, settings = validate_settings(settings)
+
+ if success then
+ load_database(self)
+ local id = get_id(settings.value.userid.value)
+ if id then
+ settings.value.userid.errtxt = "This userid already exists!"
+ success = false
+ end
+ end
+
+ if success then
+ success = write_settings(self, settings, id)
+ end
+
+ if not success then
+ settings.errtxt = "Failed to create new user"
+ end
+
+ return settings
+end
+
+delete_user = function (self, userid)
+ load_auth(self)
+ local cmdresult = "Failed to delete user"
+ if auth.delete_entry(self, userid) then
+ cmdresult = "User deleted"
+ end
+ return cfe({ value=cmdresult, label="Delete user result" })
+end