summaryrefslogtreecommitdiffstats
path: root/aconf/model/aaa.lua
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2014-03-10 22:45:18 +0200
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2014-03-24 01:18:13 +0200
commit7d9c43916b0600ac4879dfe9793eab807a83ab2b (patch)
treeec54ed64c9a557b6ea4ad88d31138a02d3e0cd04 /aconf/model/aaa.lua
parentcb6c243dc356ef1d46d7ddb96e6ea6ae007c6cca (diff)
downloadaconf-7d9c43916b0600ac4879dfe9793eab807a83ab2b.tar.bz2
aconf-7d9c43916b0600ac4879dfe9793eab807a83ab2b.tar.xz
rename ACF2 to Alpine Configurator (aconf)
Diffstat (limited to 'aconf/model/aaa.lua')
-rw-r--r--aconf/model/aaa.lua88
1 files changed, 88 insertions, 0 deletions
diff --git a/aconf/model/aaa.lua b/aconf/model/aaa.lua
new file mode 100644
index 0000000..e324381
--- /dev/null
+++ b/aconf/model/aaa.lua
@@ -0,0 +1,88 @@
+--[[
+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')