class MemberUnitTable(DynamoResource): table_name = 'member' index_name = 'member_unit' partition_key = 'unit' schema = MemberSchema @authorized(has_permission('member-read'), has_all(own_unit(), has_permission('myunit-member-read'))) def get(self, unit): fault = assert_has_unit(unit) if fault: return fault return self.list_get(unit)
class PageLogUnitTable(DynamoResource): table_name = 'page_log' partition_key = 'unit' range_key = 'timestamp' @authorized(has_permission('pagelog-read'), has_all(own_unit(), has_permission('myunit-pagelog-read'))) def get(self, unit): # TODO: pagination fault = assert_has_unit(unit) if fault: return fault return self.list_get(unit)
class ContactUnitTable(DynamoResource): table_name = 'contact' index_name = 'contact_unit' partition_key = 'unit' # Index resource, no adding entries @authorized(has_permission('contact-read'), has_all(own_unit(), has_permission('myunit-contact-read'))) def get(self, unit): fault = assert_has_unit(unit) if fault: return fault return self.list_get(unit)
class ContactTable(DynamoResource): table_name = 'contact' partition_key = 'phone_number' schema = ContactSchema @authorized(has_permission('contact-read'), has_all(own_unit(), has_permission('myunit-contact-read'))) def get(self, phone_num): return self.single_get(phone_num) @authorized(has_permission('contact-write'), has_all(own_unit(), has_permission('myunit-contact-write'))) def put(self, phone_num): item = request.form.copy() item["phone_number"] = phone_num return self.single_put(item)
class UnitTable(DynamoResource): table_name = 'unit' partition_key = 'name' schema = UnitSchema @authorized(has_permission('unit-read'), own_unit()) def get(self, unit): return self.single_get(unit) @authorized(has_permission('unit-write'), has_all(own_unit(), has_permission('myunit-unit-write'))) def put(self, unit): item = request.form.copy() item["name"] = unit return self.single_put(item)
class MemberTable(DynamoResource): table_name = 'member' partition_key = 'member_id' schema = MemberSchema @authorized(has_permission('member-read'), has_all(own_unit(), has_permission('myunit-member-read'))) def get(self, member_id): return self.single_get(member_id) @authorized(has_permission('member-write'), has_all(own_unit(), has_permission('myunit-member-write'))) def put(self, member_id): item = { 'member_id' : member_id, 'name' : request.form.get('name'), 'unit' : request.form.get('unit'), 'roles' : set(dict(request.form).get('roles', ['none'])), } return self.single_put(item)
def test_authorized(app, client, mocker): # authorized is a function decorator from web.authorize import authorized, Credentials, own_unit, has_role, has_all, has_permission get_creds = mocker.patch('web.authorize.Predicate.get_credentials') get_creds.return_value = Credentials(member_id=123, name='Test User', unit='Test', roles=set({'foo': 'bar'}), permissions=set( {'sausage', 'frankfurt'})) mf_ret = "MF" def mf(**kwargs): return mf_ret dec = authorized(own_unit()) with app.test_request_context(): assert dec(mf)(unit='Test') == "MF" assert dec(mf)(unit='NotTest') == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) assert dec(mf)()[1] == 403 assert authorized(has_role('foo'))(mf)() == "MF" assert authorized(has_role('frog'))(mf)() == ({ 'error': 'Authorization', 'detail': ["Required role not found"] }, 403) assert authorized(has_role('foo', 'frog', 'flip'))(mf)() == "MF" comb = authorized(own_unit(), has_role('foo')) assert comb(mf)(unit='Test') == "MF" assert comb(mf)(unit='NotTest') == "MF" comb = authorized(own_unit(), has_role('frog')) assert comb(mf)(unit='Test') == "MF" assert comb(mf)(unit='NotTest') == ({ 'error': 'Authorization', 'detail': ["Not the member's unit", "Required role not found"] }, 403) comb = authorized(has_all(own_unit(), has_role('foo'))) assert comb(mf)(unit='Test') == "MF" assert comb(mf)(unit='NotTest') == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) comb = authorized(has_all(own_unit(), has_role('frog'))) assert comb(mf)(unit='Test') == ({ 'error': 'Authorization', 'detail': ["Required role not found"] }, 403) assert comb(mf)(unit='NotTest') == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) assert authorized(has_permission('sausage'))(mf)() == "MF" assert authorized(has_permission('sausage', 'soup'))(mf)() == "MF" assert authorized(has_permission('soup'))(mf)() == ({ 'error': 'Authorization', 'detail': ["Required permission not found"] }, 403) assert authorized(has_permission('frankfurt'))(mf)() == "MF" # has_unit can fish the unit out of data for PUT and POST requests form_dat = authorized(own_unit()) with app.test_request_context(method='GET', data={'unit': 'Test'}): assert form_dat(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) with app.test_request_context(method='POST', data={'unit': 'Test'}): assert form_dat(mf)() == "MF" with app.test_request_context(method='PUT', data={'unit': 'Test'}): assert form_dat(mf)() == "MF" with app.test_request_context(method='GET', data={'unit': 'Other'}): assert form_dat(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) with app.test_request_context(method='POST', data={'unit': 'Other'}): assert form_dat(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) with app.test_request_context(method='PUT', data={'unit': 'Other'}): assert form_dat(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) # has_unit can act in a post-check manner # If we have a GET request and can't determine the unit the # execution continues and we check for the unit on the way out assert authorized(own_unit())(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403) mf_ret = ({'unit': 'Test'}, 200) assert authorized(own_unit())(mf)() == mf_ret # Multiple tests - OR mf_ret = ({'unit': 'Test'}, 200) pc = authorized(own_unit(), has_permission('sausage')) assert pc(mf)() == mf_ret pc = authorized(own_unit(), has_permission('soup')) assert pc(mf)() == mf_ret mf_ret = "FM" pc = authorized(own_unit(), has_permission('sausage')) assert pc(mf)() == "FM" pc = authorized(own_unit(), has_permission('soup')) assert pc(mf)() == ({ 'error': 'Authorization', 'detail': ["Required permission not found", "Not the member's unit"] }, 403) # Multiple tests - AND mf_ret = ({'unit': 'Test'}, 200) pc = authorized(has_all(own_unit(), has_permission('sausage'))) assert pc(mf)() == mf_ret pc = authorized(has_all(own_unit(), has_permission('soup'))) assert pc(mf)() == ({ 'error': 'Authorization', 'detail': ["Required permission not found"] }, 403) mf_ret = "FM" pc = authorized(has_all(own_unit(), has_permission('sausage'))) assert pc(mf)() == ({ 'error': 'Authorization', 'detail': ["Not the member's unit"] }, 403)