--[[ Copyright (c) 2012-2014 Kaarle Ritvanen See LICENSE file for license details --]] local M = require('aconf.model') local object = require('aconf.object') local digest = require('crypto').digest 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) -- TODO audit trail print('check permission', permission) if self.superuser then return true end assert(getmetatable(self).txn:fetch('/auth/permissions')[permission]) for _, role in M.node.pairs(self.roles, true) do for _, p in M.node.pairs(role.permissions, true) do if p == permission then return true end end end return false end 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' } M.register( 'auth', Authentication, { addr='/json'..require('posix').getcwd()..'/config/aaa.json', ui_name='Authentication' } ) M.permission.defaults('/auth')