summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Trask <ttrask01@yahoo.com>2016-01-24 22:24:30 +0000
committerTed Trask <ttrask01@yahoo.com>2016-01-24 22:24:30 +0000
commit43ac64370f5e8d53ecf874048c27d493c5bc01b4 (patch)
treea560b46ea47a32929e4cfa894309997cb35b2cfe
parentb42210d80281189875c652909b971fcb514ec8b2 (diff)
downloadacf-core-43ac64370f5e8d53ecf874048c27d493c5bc01b4.tar.bz2
acf-core-43ac64370f5e8d53ecf874048c27d493c5bc01b4.tar.xz
Add password.listlockevents/unlockuser/unlockip actions to acf-util
password.status now reports locked status for each user Modified session lib to add list_events/delete_events Changed session.record_event/count_events to take IP rather than hash
-rw-r--r--app/Makefile1
-rw-r--r--app/acf-util/acf-util.roles2
-rw-r--r--app/acf-util/logon-model.lua6
-rw-r--r--app/acf-util/password-controller.lua12
-rw-r--r--app/acf-util/password-listlockevents-html.lsp48
-rw-r--r--app/acf-util/password-model.lua32
-rw-r--r--app/acf-util/password-status-html.lsp6
-rw-r--r--app/acf-util/password.menu2
-rw-r--r--app/acf_www-controller.lua5
-rw-r--r--lib/session.lua70
10 files changed, 147 insertions, 37 deletions
diff --git a/app/Makefile b/app/Makefile
index 2b93f30..50a5821 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -5,6 +5,7 @@ APP_DIST= \
acf-util/logon-controller.lua \
acf-util/logon-model.lua \
acf-util/password-controller.lua \
+ acf-util/password-listlockevents-html.lsp \
acf-util/password-model.lua \
acf-util/password-status-html.lsp \
acf-util/password.menu \
diff --git a/app/acf-util/acf-util.roles b/app/acf-util/acf-util.roles
index 926b74d..4e96271 100644
--- a/app/acf-util/acf-util.roles
+++ b/app/acf-util/acf-util.roles
@@ -2,4 +2,4 @@ GUEST=logon/logon,logon/logoff,logon/status,welcome/read
DEFAULT=
USER=password/editme,roles/read
EXPERT=
-ADMIN=logon/logon,logon/logoff,logon/status,password/editme,password/status,password/edituser,password/newuser,password/deleteuser,roles/read,roles/getpermslist,roles/viewuserroles,roles/viewroleperms,roles/viewroles,roles/editrole,roles/deleterole,roles/newrole,welcome/read,password/status,password/edituser,password/newuser,password/deleteuser,roles/getpermslist,roles/viewuserroles,roles/viewroleperms,roles/viewroles,roles/editrole,roles/deleterole,roles/newrole,skins/update
+ADMIN=logon/logon,logon/logoff,logon/status,password/editme,password/status,password/edituser,password/newuser,password/deleteuser,password/listlockevents,password/unlockuser,password/unlockip,roles/read,roles/getpermslist,roles/viewuserroles,roles/viewroleperms,roles/viewroles,roles/editrole,roles/deleterole,roles/newrole,welcome/read,password/status,password/edituser,password/newuser,password/deleteuser,roles/getpermslist,roles/viewuserroles,roles/viewroleperms,roles/viewroles,roles/editrole,roles/deleterole,roles/newrole,skins/update
diff --git a/app/acf-util/logon-model.lua b/app/acf-util/logon-model.lua
index 0cfba7f..3394445 100644
--- a/app/acf-util/logon-model.lua
+++ b/app/acf-util/logon-model.lua
@@ -45,9 +45,9 @@ end
mymodule.logon = function (self, logon)
logon.errtxt = "Logon Attempt Failed"
-- Check to see if we can log on this user id / ip addr
- local countevent = session.count_events(self.conf.sessiondir, logon.value.userid.value, session.hash_ip_addr(self.conf.clientip), self.conf.lockouttime, self.conf.lockouteventlimit)
+ local countevent = session.count_events(self.conf.sessiondir, logon.value.userid.value, self.conf.clientip, self.conf.lockouttime, self.conf.lockouteventlimit)
if countevent then
- session.record_event(self.conf.sessiondir, logon.value.userid.value, session.hash_ip_addr(self.conf.clientip))
+ session.record_event(self.conf.sessiondir, logon.value.userid.value, self.conf.clientip)
end
if false == countevent then
@@ -71,7 +71,7 @@ mymodule.logon = function (self, logon)
logon.errtxt = nil
else
-- We have a bad logon, log the event
- session.record_event(self.conf.sessiondir, logon.value.userid.value, session.hash_ip_addr(self.conf.clientip))
+ session.record_event(self.conf.sessiondir, logon.value.userid.value, self.conf.clientip)
end
end
return logon
diff --git a/app/acf-util/password-controller.lua b/app/acf-util/password-controller.lua
index 264aadc..b457350 100644
--- a/app/acf-util/password-controller.lua
+++ b/app/acf-util/password-controller.lua
@@ -25,4 +25,16 @@ function mymodule.deleteuser(self)
return self.handle_form(self, self.model.get_delete_user, self.model.delete_user, self.clientdata, "Delete", "Delete User", "Deleted user")
end
+function mymodule.listlockevents(self)
+ return self.model.list_lock_events(self, self.clientdata)
+end
+
+function mymodule.unlockuser(self)
+ return self.handle_form(self, self.model.get_unlock_user, self.model.unlock_user, self.clientdata, "Unlock", "Unlock User", "Unlocked user")
+end
+
+function mymodule.unlockip(self)
+ return self.handle_form(self, self.model.get_unlock_ip, self.model.unlock_ip, self.clientdata, "Unlock", "Unlock IP Address", "Unlocked IP address")
+end
+
return mymodule
diff --git a/app/acf-util/password-listlockevents-html.lsp b/app/acf-util/password-listlockevents-html.lsp
new file mode 100644
index 0000000..81ea7f6
--- /dev/null
+++ b/app/acf-util/password-listlockevents-html.lsp
@@ -0,0 +1,48 @@
+<% local view, viewlibrary, page_info, session = ...
+htmlviewfunctions = require("htmlviewfunctions")
+html = require("acf.html")
+%>
+
+<script type="text/javascript">
+ if (typeof jQuery == 'undefined') {
+ document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery-latest.js"><\/script>');
+ }
+</script>
+
+<script type="text/javascript">
+ if (typeof $.tablesorter == 'undefined') {
+ document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery.tablesorter.js"><\/script>');
+ }
+</script>
+
+<script type="text/javascript">
+ $(document).ready(function() {
+ $("#list").tablesorter({ headers: {2:{sorter: 'ipAddress'}}, widgets: ['zebra']});
+ });
+</script>
+
+
+<% htmlviewfunctions.displaycommandresults({"unlockuser", "unlockip"}, session, true) %>
+
+<% local header_level = htmlviewfunctions.displaysectionstart(view, page_info) %>
+<table id="list" class="tablesorter"><thead>
+ <tr>
+ <th>User ID</th>
+ <th>IP Address</th>
+ <th>Time</th>
+ </tr>
+</thead><tbody>
+<% for i,lock in ipairs( view.value ) do %>
+ <tr>
+ <td><%= html.html_escape(lock.userid) %></td>
+ <td><%= html.html_escape(lock.ip) %></td>
+ <td><%= format.formattime(lock.time) %></td>
+ </tr>
+<% end %>
+</tbody></table>
+<% htmlviewfunctions.displaysectionend(header_level) %>
+
+<% if viewlibrary and viewlibrary.dispatch_component then
+ viewlibrary.dispatch_component("unlockuser")
+ viewlibrary.dispatch_component("unlockip")
+end %>
diff --git a/app/acf-util/password-model.lua b/app/acf-util/password-model.lua
index 54faf4b..72ae416 100644
--- a/app/acf-util/password-model.lua
+++ b/app/acf-util/password-model.lua
@@ -2,6 +2,7 @@ local mymodule = {}
authenticator = require("authenticator")
roles = require("roles")
+session = require("session")
avail_roles, avail_skins, avail_homes = nil
@@ -89,6 +90,7 @@ local function get_blank_user(self)
result.value.roles = cfe({ type="multi", value={}, label="Roles", option=avail_roles or {}, seq=3 })
result.value.skin = cfe({ type="select", value="", label="Skin", option=avail_skins or {""}, seq=7 })
result.value.home = cfe({ type="select", value="", label="Home", option=avail_homes or {""}, seq=6 })
+ result.value.locked = cfe({ type="boolean", value=false, label="Locked", readonly=true, seq=8 })
return result
end
@@ -96,7 +98,7 @@ end
local function get_user(self, userid)
local result = get_blank_user(self)
result.value.userid.key = true
- result.value.userid.value = userid
+ result.value.userid.value = userid or ""
if result.value.userid.value ~= "" then
result.value.userid.readonly = true
@@ -109,6 +111,7 @@ local function get_user(self, userid)
if result.value[n] and n ~= "password" then result.value[n].value = v end
end
end
+ result.value.locked.value = session.count_events(self.conf.sessiondir, result.value.userid.value)
end
return result
@@ -204,7 +207,6 @@ function mymodule.get_users(self)
for x,user in pairs(userlist) do
users[#users+1] = get_user(self, user)
end
-
return cfe({ type="group", value=users, label="User Accounts" })
end
@@ -221,4 +223,30 @@ function mymodule.delete_user(self, deleteuser)
return deleteuser
end
+function mymodule.list_lock_events(self, clientdata)
+ return cfe({type="structure", value=session.list_events(self.conf.sessiondir), label="Lock events"})
+end
+
+function mymodule.get_unlock_user(self, clientdata)
+ local retval = cfe({type="group", value={}, label="Unlock user"})
+ retval.value.userid = cfe({ label="User id" })
+ return retval
+end
+
+function mymodule.unlock_user(self, unlock)
+ session.delete_events(self.conf.sessiondir, unlock.value.userid.value)
+ return unlock
+end
+
+function mymodule.get_unlock_ip(self, clientdata)
+ local retval = cfe({type="group", value={}, label="Unlock IP address"})
+ retval.value.ip = cfe({ label="IP address" })
+ return retval
+end
+
+function mymodule.unlock_ip(self, unlock)
+ session.delete_events(self.conf.sessiondir, nil, unlock.value.ip.value)
+ return unlock
+end
+
return mymodule
diff --git a/app/acf-util/password-status-html.lsp b/app/acf-util/password-status-html.lsp
index 551f798..8845b13 100644
--- a/app/acf-util/password-status-html.lsp
+++ b/app/acf-util/password-status-html.lsp
@@ -2,7 +2,7 @@
<% htmlviewfunctions = require("htmlviewfunctions") %>
<% html = require("acf.html") %>
-<% htmlviewfunctions.displaycommandresults({"newuser", "edituser", "deleteuser"}, session) %>
+<% htmlviewfunctions.displaycommandresults({"newuser", "edituser", "deleteuser", "unlockuser"}, session) %>
<%
local header_level = htmlviewfunctions.displaysectionstart(form, page_info)
@@ -27,12 +27,16 @@ for i,user in ipairs(form.value) do
<td style='border:none;'><b><%= html.html_escape(user.value.roles.label) %></b></td>
<td style='border:none;'><%= html.html_escape(table.concat(user.value.roles.value, ", ")) %></td>
</tr><tr>
+ <td style='border:none;'><b><%= html.html_escape(user.value.locked.label) %></b></td>
+ <td style='border:none;'><%= html.html_escape(tostring(user.value.locked.value)) %></td>
+ </tr><tr>
<td style='border:none;'><b>Option</b></td>
<td style='border:none;'>
<% local userid = cfe({type="hidden", value=user.value.userid.value}) %>
<% htmlviewfunctions.displayitem(cfe({type="link", value={userid=userid, redir=redir}, label="", option="Edit", action="edituser"}), page_info, -1) %>
<% htmlviewfunctions.displayitem(cfe({type="form", value={userid=userid}, label="", option="Delete", action="deleteuser" }), page_info, -1) %>
<% htmlviewfunctions.displayitem(cfe({type="link", value={userid=userid}, label="", option="View Roles", action=page_info.script.."/acf-util/roles/viewuserroles"}), page_info, -1) %>
+ <% if (user.value.locked.value) then htmlviewfunctions.displayitem(cfe({type="form", value={userid=userid}, label="", option="Unlock", action="unlockuser"}), page_info, -1) end %>
</td>
</tr>
</tbody></table>
diff --git a/app/acf-util/password.menu b/app/acf-util/password.menu
index 1a079e1..be2091a 100644
--- a/app/acf-util/password.menu
+++ b/app/acf-util/password.menu
@@ -1,4 +1,4 @@
#CAT GROUP/DESC TAB ACTION
System 10User_management Administration status
+System 10User_management Lock_Events listlockevents
System 10User_management Edit_me editme
-
diff --git a/app/acf_www-controller.lua b/app/acf_www-controller.lua
index 614cd75..61dac76 100644
--- a/app/acf_www-controller.lua
+++ b/app/acf_www-controller.lua
@@ -277,13 +277,12 @@ mymodule.mvc.on_load = function (self, parent)
self.clientdata.sessionid)
if timestamp == nil then
-- invalid session id, report event and create new one
- sessionlib.record_event(self.conf.sessiondir, nil,
- sessionlib.hash_ip_addr(self.conf.clientip))
+ sessionlib.record_event(self.conf.sessiondir, nil, self.conf.clientip)
--self.logevent("Didn't find session")
else
--self.logevent("Found session")
-- We read in a valid session, check if it's ok
- if self.sessiondata.userinfo and self.sessiondata.userinfo.userid and sessionlib.count_events(self.conf.sessiondir, self.sessiondata.userinfo.userid, sessionlib.hash_ip_addr(self.conf.clientip), self.conf.lockouttime, self.conf.lockouteventlimit) then
+ if self.sessiondata.userinfo and self.sessiondata.userinfo.userid and sessionlib.count_events(self.conf.sessiondir, self.sessiondata.userinfo.userid, self.conf.clientip, self.conf.lockouttime, self.conf.lockouteventlimit) then
--self.logevent("Bad session, erasing")
-- Too many events on this id / ip, kill the session
sessionlib.unlink_session(self.conf.sessiondir, self.clientdata.sessionid)
diff --git a/lib/session.lua b/lib/session.lua
index 34b9789..b4965ee 100644
--- a/lib/session.lua
+++ b/lib/session.lua
@@ -35,17 +35,17 @@ mymodule.random_hash = function (size)
end
-- FIXME: only hashes ipv4
-mymodule.hash_ip_addr = function (string)
+mymodule.hash_ip_addr = function (ip)
local str = ""
- for i in string.gmatch(string, "%d+") do
+ for i in string.gmatch(ip or "", "%d+") do
str = str .. string.format("%02x", i )
end
return str
end
-mymodule.ip_addr_from_hash = function (string)
+mymodule.ip_addr_from_hash = function (hash)
local str = ""
- for i in string.gmatch(string, "..") do
+ for i in string.gmatch(hash or "", "..") do
str = str .. string.format("%d", "0x" .. i) .. "."
end
return string.sub(str, 1, string.len(str)-1)
@@ -182,41 +182,45 @@ end
-- the format is lockevent.id.datetime.processid
mymodule.record_event = function( sessionpath, id_u, id_ip )
local x = io.open (string.format ("%s/lockevent.%s.%s.%s.%s",
- sessionpath or "/", id_u or "", id_ip or "", os.time(),
+ sessionpath or "/", id_u or "", mymodule.hash_ip_addr(id_ip), os.time(),
(posix.getpid("pid")) or "" ), "w")
io.close(x)
end
--- Check how many invalid logon events
--- have happened for this id in the last n minutes
--- this will only effect the lockevent files
-mymodule.count_events = function (sessionpath, id_user, ipaddr, minutes, limit)
- --we need to have the counts added up? deny off any and or all
+-- List invalid logon events
+-- Can specify username and/or ip address to filter
+mymodule.list_events = function (sessionpath, id_user, ipaddr, minutes)
+ local list = {}
local now = os.time()
local minutes_ago = now - ((minutes or minutes_count_events) * 60)
local t = {}
--give me all lockevents then we will sort through them
local searchfor = sessionpath .. "/lockevent.*"
local t = posix.glob(searchfor)
-
- if t == nil or id_user == nil or ipaddr == nil then
- return false
- else
- local count = 0
- for a,b in pairs(t) do
- if posix.stat(b,"mtime") > minutes_ago then
- local user, ip = string.match(b, "/lockevent%.([^.]*)%.([^.]*)%.")
- if id_user == user or ipaddr == ip then
- count = count + 1
- end
+
+ local ipaddrhash = mymodule.hash_ip_addr(ipaddr)
+ for a,b in pairs(t) do
+ if posix.stat(b,"mtime") > minutes_ago then
+ local user, ip, time, pid = string.match(b, "/lockevent%.([^.]*)%.([^.]*)%.([^.]*)%.([^.]*)$")
+ if user and (not id_user or id_user == user) and (not ipaddr or ipaddrhash == ip) then
+ list[#list+1] = {userid=user, ip=mymodule.ip_addr_from_hash(ip), time=time, pid=pid}
end
end
- if count>(tonumber(limit) or limit_count_events) then
- return true
- else
- return false
- end
end
+ return list
+end
+
+-- Check how many invalid logon events
+-- have happened for this id in the last n minutes
+mymodule.count_events = function (sessionpath, id_user, ipaddr, minutes, limit)
+ local locked = false
+ local list = mymodule.list_events(sessionpath, id_user, ipaddr, minutes)
+ if #list>(tonumber(limit) or limit_count_events) then
+ locked = true
+ else
+ locked = false
+ end
+ return locked
end
-- Clear events that are older than n minutes
@@ -248,4 +252,18 @@ mymodule.expired_events = function (sessionpath, minutes)
return 0
end
+mymodule.delete_events = function (sessionpath, id_user, ipaddr)
+ --give me all lockevents then we will sort through them
+ local searchfor = sessionpath .. "/lockevent.*"
+ local t = posix.glob(searchfor)
+
+ local ipaddrhash = mymodule.hash_ip_addr(ipaddr)
+ for a,b in pairs(t) do
+ local user, ip = string.match(b, "/lockevent%.([^.]*)%.([^.]*)%.")
+ if user and (not id_user or id_user == user) and (not ipaddr or ipaddrhash == ip) then
+ os.remove(b)
+ end
+ end
+end
+
return mymodule