diff options
-rw-r--r-- | aconf/model/aaa.lua | 31 | ||||
-rw-r--r-- | server.lua | 35 |
2 files changed, 59 insertions, 7 deletions
diff --git a/aconf/model/aaa.lua b/aconf/model/aaa.lua index 01dc26a..048574a 100644 --- a/aconf/model/aaa.lua +++ b/aconf/model/aaa.lua @@ -4,6 +4,7 @@ See LICENSE file for license details --]] local M = require('aconf.model') +local node = require('aconf.model.node') local object = require('aconf.object') local digest = require('crypto').digest @@ -54,8 +55,8 @@ end function User:check_permission(permission) assert(self:fetch('/auth/permissions')[permission]) - for _, role in M.node.pairs(self.roles, true) do - for _, p in M.node.pairs(role.permissions, true) do + for _, role in node.pairs(self.roles, true) do + for _, p in node.pairs(role.permissions, true) do if p == permission then return true end end end @@ -63,14 +64,36 @@ function User:check_permission(permission) end +local Record = M.new() +Record.user = M.String{required=true, editable=false} +Record.action = M.String{required=true, editable=false} +Record.path = M.String{editable=false} +Record.data = M.String{editable=false} +Record.timestamp = M.time.Timestamp{editable=false} + + local Authentication = M.new() Authentication.users = M.Collection{type=User} Authentication.roles = M.Collection{type=Role} Authentication.permissions = M.Set{ - type=M.String, - addr='/volatile/aaa/permissions' + type=M.String, addr='/volatile/aaa/permissions' +} +Authentication.audit_trail = M.List{ + type=Record, editable=false, ui_name='Audit trail', ui_member='Record' +} +Authentication.action_log = M.List{ + type=Record, addr=node.null_addr, visible=false } +function Authentication:validate() + local time = os.time() + for _, action in node.pairs(self.action_log) do + action.timestamp = time + node.insert(self.audit_trail, action) + end +end + + M.register( 'auth', Authentication, @@ -45,8 +45,25 @@ return function(env) local success, code, headers, res, encode = xpcall( function() + local session + + local function log_action(txn, params, s) + params.user = mnode.name((s or session).user) + mnode.insert(txn:fetch('/auth/action-log'), params) + end + + local function log_session_event(action, session) + local txn = aconf.start_txn() + log_action(txn, {action=action}, session) + txn:commit() + end + + for sid, session in pairs(sessions) do - if session.expires < os.time() then sessions[sid] = nil end + if session.expires < os.time() then + sessions[sid] = nil + log_session_event('expire', session) + end end local method = env.REQUEST_METHOD @@ -67,7 +84,6 @@ return function(env) end end - local session function reset_session_expiry() session.expires = os.time() + 600 end local sid = tonumber(env.HTTP_X_ACONF_AUTH_TOKEN) @@ -91,6 +107,8 @@ return function(env) session = {user=user, last_txn_id=0, txns={}} reset_session_expiry() sessions[sid] = session + log_session_event('login') + return 204, { ['X-AConf-Auth-Token']=sid, ['X-AConf-Save-Required']=save_req and 1 or 0 @@ -103,6 +121,7 @@ return function(env) if method == 'DELETE' then sessions[sid] = nil + log_session_event('logout') return 204 end @@ -184,6 +203,11 @@ return function(env) return 200, nil, res end + local jdata = json.encode(data) + local function log_obj_action(action) + log_action(txn, {action=action, path=path, data=jdata}) + end + if method == 'POST' then local obj = txn:fetch(path) @@ -194,8 +218,11 @@ return function(env) data = data.data end mnode.insert(obj, data, index) + log_obj_action('insert') - elseif type(obj) == 'function' then res = obj(data) + elseif type(obj) == 'function' then + res = obj(data) + log_obj_action('invoke') else return 405 end @@ -203,10 +230,12 @@ return function(env) if method == 'DELETE' then if parent[name] == nil then return 404 end parent[name] = nil + log_obj_action('delete') elseif method == 'PUT' then if isinstance(parent, mnode.Set) then return 405 end parent[name] = data + log_obj_action('set') else return 405 end end |