diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-07-22 19:58:39 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-07-22 19:58:39 +0000 |
commit | 8cfe28d0691856222685b93f4a58664416a0aa65 (patch) | |
tree | bdc57542af8a67aefbd4b587b6aa9d5483ca3e55 | |
parent | a1ad49891bbeea6c4c5cf77a574d219c9a722eab (diff) | |
download | acf-core-8cfe28d0691856222685b93f4a58664416a0aa65.tar.bz2 acf-core-8cfe28d0691856222685b93f4a58664416a0aa65.tar.xz |
Split common code out of authenticator-plaintext into authenticator.lua in preparation for adding SQL authentication. Rewrote authentication functions to use cfe's. Made corresponding changes to roles and logon. Added dnsfiles field to userdata for tinydns access control.
git-svn-id: svn://svn.alpinelinux.org/acf/core/trunk@1314 ab2d0c66-481e-0410-8bed-d214d4d58bed
-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 |