diff options
author | Ted Trask <ttrask01@yahoo.com> | 2010-07-01 12:42:51 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2010-07-01 12:42:51 +0000 |
commit | 2536d0c904364e560b5fc2c4ab0460739426b274 (patch) | |
tree | 8f217baf5dcb484711d2cac04d2746ca351a0e86 /did-model.lua | |
parent | 072e06ced2652119c9c1d6fcd2fddeba8cd6445c (diff) | |
download | acf-did-2536d0c904364e560b5fc2c4ab0460739426b274.tar.bz2 acf-did-2536d0c904364e560b5fc2c4ab0460739426b274.tar.xz |
Added user/roles permissions on a DID-by-DID basis.
Diffstat (limited to 'did-model.lua')
-rw-r--r-- | did-model.lua | 287 |
1 files changed, 235 insertions, 52 deletions
diff --git a/did-model.lua b/did-model.lua index d7b3a8d..0e2fb81 100644 --- a/did-model.lua +++ b/did-model.lua @@ -5,6 +5,8 @@ require("modelfunctions") require("format") require("validator") require("luasql.postgres") +require("authenticator") +require("roles") -- NOTE -- This is the SQL statement that should be run by the VoIP server to figure out the current extension for a DID -- "SELECT extension FROM pubdid WHERE did='$1' AND 'now'>=starttime AND 'now'<endtime ORDER BY stale LIMIT 1" @@ -22,6 +24,8 @@ local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin local env local con +local didlist + local database_creation_script = { "CREATE AGGREGATE array_accum(anyelement) (SFUNC = array_append, STYPE = anyarray, INITCOND = '{}')", "CREATE TABLE dbhistlog (logdatetime timestamp(3) without time zone NOT NULL, msgtext text, userid text)", @@ -183,7 +187,7 @@ local groomdbhistlog = function() logme("removed " .. res .. " old dbhistlog lines") end -local generatewhereclause = function(did, extension, identification, description, department, clause) +local generatewhereclause = function(did, extension, identification, description, department, allowedlist, clause) local sql = "" local where = {} -- We're going to use regular expressions so can search for substrings @@ -203,6 +207,10 @@ local generatewhereclause = function(did, extension, identification, description if department and department ~= "" then where[#where+1] = "department ~* '"..escaperegex(department).."'" end + --if allowedlist and #allowedlist > 0 then + if allowedlist then + where[#where+1] = "definition.did IN ('"..table.concat(allowedlist, "', '").."')" + end if #where > 0 then sql = " " .. (clause or "WHERE") .. " " .. table.concat(where, " AND ") end @@ -230,14 +238,14 @@ local getdefinitionentries = function(sql) return entries end -local listunuseddefinitions = function(did, identification, description, department, page) - local where = generatewhereclause(did, nil, identification, description, department, "AND") +local listunuseddefinitions = function(did, identification, description, department, allowedlist, page) + local where = generatewhereclause(did, nil, identification, description, department, allowedlist, "AND") local sql = "SELECT * FROM definition WHERE did NOT IN (SELECT did FROM rule)"..where.." ORDER BY did"..generatelimitclause(page) return getdefinitionentries(sql) end -local countunuseddefinitions = function(did, identification, description, department) - local where = generatewhereclause(did, nil, identification, description, department, "AND") +local countunuseddefinitions = function(did, identification, description, department, allowedlist) + local where = generatewhereclause(did, nil, identification, description, department, allowedlist, "AND") local sql = "SELECT count(*) FROM definition WHERE did NOT IN (SELECT did FROM rule)"..where cur = assert (con:execute(sql)) local count = cur:fetch() @@ -246,8 +254,8 @@ local countunuseddefinitions = function(did, identification, description, depart end -- Lists only the definitions that have rules, this also allows us to select based upon extension -local listuseddefinitions = function(did, extension, identification, description, department, page) - local where = string.gsub(generatewhereclause(did, extension, identification, description, department, "HAVING"), "extension", "array_to_string(array_accum(rule.extension), ', ')") +local listuseddefinitions = function(did, extension, identification, description, department, allowedlist, page) + local where = string.gsub(generatewhereclause(did, extension, identification, description, department, allowedlist, "HAVING"), "extension", "array_to_string(array_accum(rule.extension), ', ')") -- Combine with rules to get extensions, this will drop all dids that don't have rules -- Relies on this custom aggregate function being defined -- local sql = "CREATE AGGREGATE array_accum(anyelement)(sfunc = array_append, stype = anyarray, initcond = '{}')" @@ -257,8 +265,8 @@ local listuseddefinitions = function(did, extension, identification, description end -- Counts only the definitions that have rules, this also allows us to select based upon extension -local countuseddefinitions = function(did, extension, identification, description, department) - local where = string.gsub(generatewhereclause(did, extension, identification, description, department, "HAVING"), "extension", "array_to_string(array_accum(rule.extension), ', ')") +local countuseddefinitions = function(did, extension, identification, description, department, allowedlist) + local where = string.gsub(generatewhereclause(did, extension, identification, description, department, allowedlist, "HAVING"), "extension", "array_to_string(array_accum(rule.extension), ', ')") -- Combine with rules to get extensions, this will drop all dids that don't have rules -- Relies on this custom aggregate function being defined -- local sql = "CREATE AGGREGATE array_accum(anyelement)(sfunc = array_append, stype = anyarray, initcond = '{}')" @@ -271,8 +279,8 @@ local countuseddefinitions = function(did, extension, identification, descriptio return count end -local listdefinitionsandextensions = function(did, identification, description, department, page) - local where = generatewhereclause(did, nil, identification, description, department, "HAVING") +local listdefinitionsandextensions = function(did, identification, description, department, allowedlist, page) + local where = generatewhereclause(did, nil, identification, description, department, allowedlist, "HAVING") -- Combine with rules to get extensions, use LEFT JOIN to not drop all dids that don't have rules -- Relies on this custom aggregate function being defined -- local sql = "CREATE AGGREGATE array_accum(anyelement)(sfunc = array_append, stype = anyarray, initcond = '{}')" @@ -281,21 +289,21 @@ local listdefinitionsandextensions = function(did, identification, description, return getdefinitionentries(sql) end -local listdefinitions = function(did, identification, description, department, page) - local sql = "SELECT * FROM definition"..generatewhereclause(did, nil, identification, description, department).." ORDER BY did"..generatelimitclause(page) +local listdefinitions = function(did, identification, description, department, allowedlist, page) + local sql = "SELECT * FROM definition"..generatewhereclause(did, nil, identification, description, department, allowedlist).." ORDER BY did"..generatelimitclause(page) return getdefinitionentries(sql) end -local countdefinitions = function(did, identification, description, department) - local sql = "SELECT count(*) FROM definition"..generatewhereclause(did, nil, identification, description, department) +local countdefinitions = function(did, identification, description, department, allowedlist) + local sql = "SELECT count(*) FROM definition"..generatewhereclause(did, nil, identification, description, department, allowedlist) cur = assert (con:execute(sql)) local count = cur:fetch() cur:close() return count end -local listdefs = function(did, identification, description, department) - local sql = "SELECT did FROM definition"..generatewhereclause(did, nil, identification, description, department).." ORDER BY did" +local listdefs = function(did, identification, description, department, allowedlist) + local sql = "SELECT did FROM definition"..generatewhereclause(did, nil, identification, description, department, allowedlist).." ORDER BY did" local entries = {} cur = assert (con:execute(sql)) row = cur:fetch ({}, "a") @@ -759,17 +767,56 @@ local determinepagedata = function(count, page) return page_data end +local function parseentry(entry) + local allowedlist = {} + local restricted = (string.find(entry, "^true:") ~= nil) + for x in string.gmatch(string.match(entry, "[^:]*$") or "", "([^,]+),?") do + allowedlist[#allowedlist + 1] = x + end + return restricted, allowedlist +end + +local function getallowedlist(self, userid) + local entry = authenticator.auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + + -- also check to see if there are allowed files for this user's roles + local rols = authenticator.get_userinfo_roles(self, userid) + -- add in the guest role + rols.value[#rols.value + 1] = roles.guest_role + for i,role in ipairs(rols.value) do + local entry = authenticator.auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + local restricted2, allowed2 + restricted2, allowed2 = parseentry(entry) + restricted = restricted or restricted2 + for i,x in ipairs(allowed2) do allowedlist[#allowedlist + 1] = x end + end + if not restricted then return nil end + return allowedlist +end + +local function adduserpermission(self, userid, did) + local entry = authenticator.auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + allowedlist[#allowedlist+1] = did + + authenticator.auth.write_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid, tostring(restricted)..":"..(table.concat(allowedlist, ",") or "")) +end + -- ################################################################################ -- PUBLIC FUNCTIONS -function getuseddefinitionlist(did, extension, identification, description, department, page) +function getuseddefinitionlist(self, userid, did, extension, identification, description, department, page) local def = createdefinitionlist(stripdash(did), extension, identification, description, department) def.label = "Used "..def.label + local allowedlist = getallowedlist(self, userid) local res, err = pcall(function() local connected = databaseconnect(DatabaseUser) - local count = countuseddefinitions(stripdash(did), extension, identification, description, department) + local count = countuseddefinitions(stripdash(did), extension, identification, description, department, allowedlist) def.value.pagedata.value = determinepagedata(count, page) - def.value.definitions.value = listuseddefinitions(stripdash(did), extension, identification, description, department, def.value.pagedata.value.page) + def.value.definitions.value = listuseddefinitions(stripdash(did), extension, identification, description, department, allowedlist, def.value.pagedata.value.page) if connected then databasedisconnect() end end) if not res then @@ -781,15 +828,16 @@ function getuseddefinitionlist(did, extension, identification, description, depa return def end -function getunuseddefinitionlist(did, identification, description, department, page) +function getunuseddefinitionlist(self, userid, did, identification, description, department, page) local def = createdefinitionlist(stripdash(did), nil, identification, description, department) def.value.extension = nil def.label = "Unused "..def.label + local allowedlist = getallowedlist(self, userid) local res, err = pcall(function() local connected = databaseconnect(DatabaseUser) - local count = countunuseddefinitions(stripdash(did), identification, description, department) + local count = countunuseddefinitions(stripdash(did), identification, description, department, allowedlist) def.value.pagedata.value = determinepagedata(count, page) - def.value.definitions.value = listunuseddefinitions(stripdash(did), identification, description, department, def.value.pagedata.value.page) + def.value.definitions.value = listunuseddefinitions(stripdash(did), identification, description, department, allowedlist, def.value.pagedata.value.page) if connected then databasedisconnect() end end) if not res then @@ -801,19 +849,20 @@ function getunuseddefinitionlist(did, identification, description, department, p return def end -function getdefinitionlist(did, extension, identification, description, department, page) +function getdefinitionlist(self, userid, did, extension, identification, description, department, page) local def = createdefinitionlist(stripdash(did), extension, identification, description, department) --def.value.extension = nil + local allowedlist = getallowedlist(self, userid) local res, err = pcall(function() local connected = databaseconnect(DatabaseUser) if def.value.extension.value == "" then - local count = countdefinitions(stripdash(did), identification, description, department) + local count = countdefinitions(stripdash(did), identification, description, department, allowedlist) def.value.pagedata.value = determinepagedata(count, page) - def.value.definitions.value = listdefinitionsandextensions(stripdash(did), identification, description, department, def.value.pagedata.value.page) + def.value.definitions.value = listdefinitionsandextensions(stripdash(did), identification, description, department, allowedlist, def.value.pagedata.value.page) else - local count = countuseddefinitions(stripdash(did), extension, identification, description, department) + local count = countuseddefinitions(stripdash(did), extension, identification, description, department, allowedlist) def.value.pagedata.value = determinepagedata(count, page) - def.value.definitions.value = listuseddefinitions(stripdash(did), extension, identification, description, department, def.value.pagedata.value.page) + def.value.definitions.value = listuseddefinitions(stripdash(did), extension, identification, description, department, allowedlist, def.value.pagedata.value.page) end if connected then databasedisconnect() end end) @@ -826,11 +875,12 @@ function getdefinitionlist(did, extension, identification, description, departme return def end -function searchdefinitions(did) +function searchdefinitions(self, userid, did) + local allowedlist = getallowedlist(self, userid) local result = {} local res, err = pcall(function() local connected = databaseconnect(DatabaseUser) - result = listdefs(did) + result = listdefs(did, nil, nil, nil, allowedlist) if connected then databasedisconnect() end end) if not res then @@ -839,7 +889,8 @@ function searchdefinitions(did) return cfe({ type="list", value=result, label="DID list" }) end -function getdefinition(did) +function getdefinition(self, userid, did) + local allowedlist = getallowedlist(self, userid) local errtxt local group = {} group.did = cfe({ value=stripdash(did) or "", label="DID" }) @@ -852,7 +903,7 @@ function getdefinition(did) group.did.errtxt = "DID does not exist" local res, err = pcall(function() local connected = databaseconnect(DatabaseUser) - local definition = listdefinitions(stripdash(did)) + local definition = listdefinitions(stripdash(did), nil, nil, nil, allowedlist) local rules = listrules(stripdash(did)) if connected then databasedisconnect() end if #definition == 1 then @@ -877,7 +928,8 @@ function getdefinition(did) end -- If exists true, then make sure exists first, if false or undefined, make sure doesn't exist -function savedefinition(defin, test, exists) +function savedefinition(self, userid, defin, test, exists) + local allowedlist = getallowedlist(self, userid) -- remove blank entries, if present defin.value.rules.value = string.gsub("\n"..format.dostounix(defin.value.rules.value), "\n%s*,%s*,%s*,%s*,%s*,%s*0000000", "") defin.value.rules.value = string.gsub(defin.value.rules.value, "$\n", "") @@ -909,7 +961,7 @@ function savedefinition(defin, test, exists) else connected = databaseconnect(DatabaseUser) end - local def = listdefinitions(definition.did) + local def = listdefinitions(definition.did, nil, nil, nil, allowedlist) if #def > 0 and not exists then defin.value.did.errtxt = "DID Number already exists" elseif #def == 0 and exists then @@ -955,18 +1007,19 @@ function savedefinition(defin, test, exists) return defin end -function updatedefinition(defin, test) - return savedefinition(defin, test, true) +function updatedefinition(self, userid, defin, test) + return savedefinition(self, userid, defin, test, true) end -function deletedefinition(did) +function deletedefinition(self, userid, did) + local allowedlist = getallowedlist(self, userid) local result = cfe({ label="Delete DID Number Result", errtxt="DID Number does not exist" }) did = stripdash(did) local res, err = pcall(function() databasedisconnect() local pw = format.parse_ini_file(fs.read_file(configfile) or "", "", "password") or "" databaseconnect(DatabaseOwner, pw) - local def = listdefs(did) + local def = listdefs(did, nil, nil, nil, allowedlist) if #def == 1 then deletedefinitionentry(did) result.value = "DID Number Deleted" @@ -1035,16 +1088,13 @@ function publishdefinition(did) local res, err = pcall(function() databasedisconnect() databaseconnect(DatabaseOwner, pw) - local dids = listdefs() - for i,d in ipairs(dids) do - if d == did then - local rules = getdailyentry(did) - publishrules(did, rules) - errtxt = nil - result = "Published DID rules" - --logme("Published DID "..did) - break - end + local def = listdefs(did) + if #def == 1 then + local rules = getdailyentry(did) + publishrules(did, rules) + errtxt = nil + result = "Published DID rules" + --logme("Published DID "..did) end databasedisconnect() end) @@ -1061,14 +1111,14 @@ function publishalldefinitions() local res, err = pcall(function() databasedisconnect() databaseconnect(DatabaseOwner, pw) - local dids = listdefs() + didlist = didlist or listdefs() local time = os.time() - for i,did in ipairs(dids) do + for i,did in ipairs(didlist) do local rules = getdailyentry(did, time) publishrules(did, rules) end - result = "Published "..#dids.." DID rules" - logme("Publishing "..#dids.." DIDs took "..os.time()-time.." seconds") + result = "Published "..#didlist.." DID rules" + logme("Publishing "..#didlist.." DIDs took "..os.time()-time.." seconds") groomdbhistlog() databasedisconnect() end) @@ -1171,3 +1221,136 @@ function getactivitylog() return retval end + +function getpermissionslist(self) + local users = authenticator.list_users(self) + local userlist = {} + for i,user in ipairs(users) do + local entry = authenticator.auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, user) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + userlist[#userlist + 1] = {id=user, restricted=restricted, allowed=allowedlist} + end + -- Need to check for roles as well as users + local rolelist = {} + local rols = roles.list_all_roles(self) + for i,role in ipairs(rols) do + local entry = authenticator.auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + rolelist[#rolelist + 1] = {id=role, restricted=restricted, allowed=allowedlist} + end + table.sort(userlist, function(a,b) return a.id < b.id end) + return cfe({ type="structure", value={user=userlist, role=rolelist}, label="DID Permissions" }) +end + +local function validatepermissions(permissions) + local success = true + if not didlist then + local res, err = pcall(function() + local connected = databaseconnect(DatabaseUser) + didlist = listdefs() + if connected then databasedisconnect() end + end) + if not res then + permissions.value.allowed.errtxt = err + success = false + end + end + if success then + local newlist = {} + if not reversedidlist then + reversedidlist = {} + for i,d in ipairs(didlist) do + reversedidlist[d] = i + end + end + for i,d in ipairs(permissions.value.allowed.value) do + local nd = stripdash(d) + newlist[#newlist+1] = nd + if not reversedidlist[nd] then + success = false + permissions.value.allowed.errtxt = "Contains invalid DID" + break + end + end + permissions.value.allowed.value = newlist + end + return success +end + +local function validateuserpermissions(self, userpermissions) + local success = false + userpermissions.value.userid.errtxt = "Invalid user" + local users = authenticator.list_users(self) + for i,user in ipairs(users) do + if userpermissions.value.userid.value == user then + userpermissions.value.userid.errtxt = nil + success = true + break + end + end + success = validatepermissions(userpermissions) and success + return success, userpermissions +end + +local function validaterolepermissions(self, rolepermissions) + local success = false + rolepermissions.value.role.errtxt = "Invalid role" + local rols = roles.list_all_roles(self) + for i,role in ipairs(rols) do + if rolepermissions.value.role.value == role then + rolepermissions.value.role.errtxt = nil + success = true + break + end + end + success = validatepermissions(rolepermissions) and success + return success, rolepermissions +end + +function getuserpermissions(self, userid) + local entry = authenticator.auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + local allowed = cfe({ type="list", value=allowedlist, label="DID Permissions", descr="List one DID per line" }) + local restrict = cfe({ type="boolean", value=restricted, label="Enable Restrictions" }) + local user = cfe({ value=userid, label="User Name" }) + local output = cfe({ type="group", value={userid=user, allowed=allowed, restricted=restrict}, label="DID Permissions" }) + validateuserpermissions(self, output) + return output +end + +function setuserpermissions(self, userpermissions) + local success, userpermissions = validateuserpermissions(self, userpermissions) + + if success then + authenticator.auth.write_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userpermissions.value.userid.value, tostring(userpermissions.value.restricted.value)..":"..(table.concat(userpermissions.value.allowed.value, ",") or "")) + else + userpermissions.errtxt = "Failed to set user permissions" + end + return userpermissions +end + +function getrolepermissions(self, role) + local entry = authenticator.auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + local restricted, allowedlist + restricted, allowedlist = parseentry(entry) + local allowed = cfe({ type="list", value=allowedlist, label="DID Permissions", descr="List one DID per line" }) + local restrict = cfe({ type="boolean", value=restricted, label="Enable Restrictions" }) + local rol = cfe({ value=role, label="Role" }) + local output = cfe({ type="group", value={role=rol, allowed=allowed, restricted=restrict}, label="DID Permissions" }) + validaterolepermissions(self, output) + return output +end + +function setrolepermissions(self, rolepermissions) + local success, rolepermissions = validaterolepermissions(self, rolepermissions) + + if success then + authenticator.auth.write_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, rolepermissions.value.role.value, tostring(rolepermissions.value.restricted.value)..":"..(table.concat(rolepermissions.value.allowed.value, ",") or "")) + else + rolepermissions.errtxt = "Failed to set role permissions" + end + return rolepermissions +end |