--[[ Copyright (c) 2012-2015 Kaarle Ritvanen 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 local conf_addr = '/json'..require('posix').getcwd()..'/config' local Role = M.new() Role.permissions = M.Set{type=M.Reference{scope='../../../permissions'}} local function hash_password(algorithm, salt, password) return algorithm..'$'..salt..'$'..digest(algorithm, salt..password) end local hash_pattern = '^(%w+)%$(%w+)%$%x+$' local Password = object.class(M.String) function Password:init() object.super(self, Password):init{detail=true} end function Password:normalize(context, value) if value:find(hash_pattern) then return value end local salt = '' for i = 1,12 do local c = math.random(48, 109) if c > 57 then c = c + 7 end if c > 90 then c = c + 6 end salt = salt..string.char(c) end return hash_password('sha256', salt, value) end local User = M.new() User.password = Password User.real_name = M.String User.superuser = M.Boolean{default=false} User.roles = M.Set{type=M.Reference{scope='../../../roles'}} function User:check_password(password) if not self.password then return false end local _, _, algorithm, salt = self.password:find(hash_pattern) if not salt then return false end return hash_password(algorithm, salt, password) == self.password end function User:check_permission(permission) assert(self:fetch('/aaa/permissions')[permission]) 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 return false 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 Aaa = M.new() Aaa.users = M.Collection{type=User} Aaa.roles = M.Collection{type=Role} Aaa.permissions = M.Set{ type=M.String, addr='/volatile/aaa/permissions', editable=false } Aaa.audit_trail = M.List{ type=Record, addr=conf_addr..'/audit.json', editable=false, ui_name='Audit trail', ui_member='Record' } Aaa.action_log = M.List{type=Record, addr=node.null_addr, visible=false} function Aaa:validate() local time = os.time() for _, action in pairs(self.action_log) do action.timestamp = time node.insert(self.audit_trail, action) end end M.register('aaa', Aaa, {addr=conf_addr..'/auth.json', ui_name='AAA'}) M.permission.defaults('/aaa')