From c832941ab3abff5d1ea826ac8a5ad36c6cb4006d Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Mon, 25 Mar 2013 23:11:53 +0200 Subject: basic access control --- acf/init.lua | 4 +++- acf/model/aaa.lua | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ acf/model/init.lua | 16 ++------------- acf/model/model.lua | 6 ++++++ acf/model/node.lua | 13 ++++++++++++ acf/model/permission.lua | 18 ++++++++++++++++ acf/model/root.lua | 24 ++++++++++++++++++++++ acf/modules/aaa.lua | 26 ------------------------ acf/modules/awall.lua | 2 ++ acf/transaction/init.lua | 2 +- 10 files changed, 122 insertions(+), 42 deletions(-) create mode 100644 acf/model/aaa.lua create mode 100644 acf/model/permission.lua create mode 100644 acf/model/root.lua delete mode 100644 acf/modules/aaa.lua (limited to 'acf') diff --git a/acf/init.lua b/acf/init.lua index b20d1a1..341c0f0 100644 --- a/acf/init.lua +++ b/acf/init.lua @@ -5,9 +5,11 @@ See LICENSE file for license details module(..., package.seeall) +require 'acf.model' +require 'acf.model.aaa' + require('acf.loader').loadmods('modules') -require 'acf.model' call = require('acf.error').call require 'acf.object' require 'acf.path' diff --git a/acf/model/aaa.lua b/acf/model/aaa.lua new file mode 100644 index 0000000..93f07dc --- /dev/null +++ b/acf/model/aaa.lua @@ -0,0 +1,53 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local M = require('acf.model') + +Role = M.new() +Role.permissions = M.Set{type=M.Reference{scope='../../../permissions'}} + + +User = M.new() +User.password = M.String +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) return 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:search('/auth/permissions')[permission]) + + for _, role in M.node.pairs(self.roles) do + for _, p in M.node.pairs(role.permissions) do + if p == permission then return true end + end + end + return false +end + + +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', + '/json'..require('lfs').currentdir()..'/config/aaa.json', + Authentication +) + +M.permission.defaults('/auth') diff --git a/acf/model/init.lua b/acf/model/init.lua index 71d0744..bf67f98 100644 --- a/acf/model/init.lua +++ b/acf/model/init.lua @@ -17,6 +17,8 @@ new = model.new local to_field = model.to_field node = require('acf.model.node') +permission = require('acf.model.permission') +register = require('acf.model.root').register set = require('acf.model.set') local object = require('acf.object') @@ -32,8 +34,6 @@ require 'stringy' -- TODO object-specific actions --- TODO access control - local Primitive = class(Field) @@ -220,15 +220,3 @@ function Mixed:save(context, value) if type(value) == 'table' then super(self, Mixed):save(context, value) else Primitive.save(self, context, value) end end - - - -RootModel = new() - -function RootModel:init(txn) - super(self, RootModel):init{txn=txn, path='/', addr='/volatile'} -end - -function register(name, addr, field) - RootModel[name] = to_field(field, addr) -end diff --git a/acf/model/model.lua b/acf/model/model.lua index 0a312a3..365fe20 100644 --- a/acf/model/model.lua +++ b/acf/model/model.lua @@ -103,4 +103,10 @@ function Model:init(context) if not field.compute then field:validate_saved() end end end + + if self.has_permission then + function mt.has_permission(user, permission) + return self:has_permission(user, permission) + end + end end diff --git a/acf/model/node.lua b/acf/model/node.lua index 3960b90..09e3d69 100644 --- a/acf/model/node.lua +++ b/acf/model/node.lua @@ -57,6 +57,18 @@ function TreeNode:init(context) function mt.__index(t, k) return mt.get(k) end function mt.__newindex(t, k, v) mt.set(k, v) end + function mt.has_permission(user, permission) + local p = permission..mt.path + if mt.txn:search('/auth/permissions')[p] then + return user:check_permission(p) + end + + if ({create=true, delete=true})[permission] then + permission = 'modify' + end + return has_permission(mt.parent, user, permission) + end + mt.txn.validable[mt.path] = mt.addr end @@ -117,6 +129,7 @@ local function meta_func(attr) end addr = meta_func('addr') +has_permission = meta_func('has_permission') members = meta_func('members') meta = meta_func('meta') mmeta = meta_func('mmeta') diff --git a/acf/model/permission.lua b/acf/model/permission.lua new file mode 100644 index 0000000..9a6d1d4 --- /dev/null +++ b/acf/model/permission.lua @@ -0,0 +1,18 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local add = require('acf.model.set').add +local start = require('acf.transaction').start + +function define(path, ...) + local txn = start() + local db = txn:search('/auth/permissions') + for _, permission in ipairs(arg) do add(db, permission..path) end + txn:commit() +end + +function defaults(path) define(path, 'read', 'create', 'modify', 'update') end diff --git a/acf/model/root.lua b/acf/model/root.lua new file mode 100644 index 0000000..a786064 --- /dev/null +++ b/acf/model/root.lua @@ -0,0 +1,24 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local model = require('acf.model.model') +local super = require('acf.object').super + + +RootModel = model.new() + +function RootModel:init(txn) + super(self, RootModel):init{txn=txn, path='/', addr='/volatile'} +end + +function RootModel:has_permission(user, permission) + return permission == 'read' +end + +function register(name, addr, field) + RootModel[name] = model.to_field(field, addr) +end diff --git a/acf/modules/aaa.lua b/acf/modules/aaa.lua deleted file mode 100644 index e98e686..0000000 --- a/acf/modules/aaa.lua +++ /dev/null @@ -1,26 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -module(..., package.seeall) - -local M = require('acf.model') - -Role = M.new() -Role.permissions = M.Set{type=M.Reference{scope='../../../permissions'}} - -User = M.new() -User.password = M.String -User.real_name = M.String -User.roles = M.Set{type=M.Reference{scope='../../../roles'}} -function User:check_password(password) return password == self.password end - -Authentication = M.new() -Authentication.users = M.Collection{type=User} -Authentication.roles = M.Collection{type=Role} -Authentication.permissions = M.Set{type=M.String} - -M.register('auth', - '/json'..require('lfs').currentdir()..'/config/aaa.json', - Authentication) diff --git a/acf/modules/awall.lua b/acf/modules/awall.lua index 2920bdb..fa120c6 100644 --- a/acf/modules/awall.lua +++ b/acf/modules/awall.lua @@ -125,3 +125,5 @@ AWall.ipset = M.Collection{type=IPSet} M.register('awall', '/json'..require('lfs').currentdir()..'/config/awall.json', AWall) + +M.permission.defaults('/awall') diff --git a/acf/transaction/init.lua b/acf/transaction/init.lua index 586e6bb..48b1832 100644 --- a/acf/transaction/init.lua +++ b/acf/transaction/init.lua @@ -6,7 +6,7 @@ See LICENSE file for license details module(..., package.seeall) local ErrorDict = require('acf.error').ErrorDict -local RootModel = require('acf.model').RootModel +local RootModel = require('acf.model.root').RootModel local object = require('acf.object') local super = object.super local pth = require('acf.path') -- cgit v1.2.3