diff options
-rw-r--r-- | app/acf-util/logon-model.lua | 22 | ||||
-rwxr-xr-x | app/acf-util/password-controller.lua | 132 | ||||
-rwxr-xr-x | app/acf-util/password-model.lua | 112 | ||||
-rwxr-xr-x | app/acf-util/password-status-html.lsp | 3 | ||||
-rw-r--r-- | app/acf-util/roles-model.lua | 4 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/authenticator-plaintext.lua | 327 | ||||
-rw-r--r-- | lib/authenticator.lua | 293 |
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 |