Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/dao/hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def propagate_changes(cont_name, _id, query, update):
cont_name and _id refer to top level container (which will not be modified here)
"""


if cont_name == 'groups':
project_ids = [p['_id'] for p in config.db.projects.find({'group': _id}, [])]
session_ids = [s['_id'] for s in config.db.sessions.find({'project': {'$in': project_ids}}, [])]
Expand All @@ -154,6 +155,8 @@ def propagate_changes(cont_name, _id, query, update):
config.db.sessions.update_many(session_q, update)
config.db.acquisitions.update_many(acquisition_q, update)


# Apply change to projects
elif cont_name == 'projects':
session_ids = [s['_id'] for s in config.db.sessions.find({'project': _id}, [])]

Expand Down
40 changes: 31 additions & 9 deletions api/handlers/listhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def _initialize_request(self, cont_name, list_name, _id, query_params=None):
query_params = None
container = storage.get_container(_id, query_params)
if container is not None:
if self.superuser_request:
if self.superuser_request or self.user_is_admin:
permchecker = always_ok
elif self.public_request:
permchecker = listauth.public_request(self, container)
Expand All @@ -209,35 +209,57 @@ class PermissionsListHandler(ListHandler):
def post(self, cont_name, list_name, **kwargs):
_id = kwargs.get('cid')
result = super(PermissionsListHandler, self).post(cont_name, list_name, **kwargs)
self._propagate_project_permissions(cont_name, _id)
payload = self.request.json_body

if cont_name == 'groups' and self.request.params.get('propagate') =='true':
self._propagate_permissions(cont_name, _id, query={'permissions._id' : payload['_id']}, update={'$set': {'permissions.$.access': payload['access']}})
self._propagate_permissions(cont_name, _id, query={'permissions._id': {'$ne': payload['_id']}}, update={'$addToSet': {'permissions': payload}})
elif cont_name != 'groups':
self._propagate_permissions(cont_name, _id)
return result

def put(self, cont_name, list_name, **kwargs):
_id = kwargs.get('cid')

result = super(PermissionsListHandler, self).put(cont_name, list_name, **kwargs)
self._propagate_project_permissions(cont_name, _id)
payload = self.request.json_body
payload['_id'] = kwargs.get('_id')
if cont_name == 'groups' and self.request.params.get('propagate') =='true':
self._propagate_permissions(cont_name, _id, query={'permissions._id' : payload['_id']}, update={'$set': {'permissions.$.access': payload['access']}})
elif cont_name != 'groups':
self._propagate_permissions(cont_name, _id)
return result

def delete(self, cont_name, list_name, **kwargs):
_id = kwargs.get('cid')
result = super(PermissionsListHandler, self).delete(cont_name, list_name, **kwargs)
self._propagate_project_permissions(cont_name, _id)

if cont_name == 'groups' and self.request.params.get('propagate') =='true':
self._propagate_permissions(cont_name, _id, query={'permissions._id' : kwargs.get('_id')}, update={'$pull' : {'permissions': {'_id': kwargs.get('_id')}}})
elif cont_name != 'groups':
self._propagate_permissions(cont_name, _id)
return result

def _propagate_project_permissions(self, cont_name, _id):
def _propagate_permissions(self, cont_name, _id, query=None, update=None):
"""
method to propagate permissions from a project to its sessions and acquisitions
method to propagate permissions from a container/group to its sessions and acquisitions
"""
if cont_name == 'projects':
if query is None:
query = {}
if cont_name == 'groups':
try:
hierarchy.propagate_changes(cont_name, _id, query, update)
except APIStorageException as e:
self.abort(400, e.message)
elif cont_name == 'projects':
try:
oid = bson.ObjectId(_id)
update = {'$set': {
'permissions': config.db.projects.find_one({'_id': oid},{'permissions': 1})['permissions']
'permissions': config.db[cont_name].find_one({'_id': oid},{'permissions': 1})['permissions']
}}
hierarchy.propagate_changes(cont_name, oid, {}, update)
except APIStorageException:
self.abort(500, 'permissions not propagated from project {} to sessions'.format(_id))
self.abort(500, 'permissions not propagated from {} {} down hierarchy'.format(cont_name, _id))


class NotesListHandler(ListHandler):
Expand Down
96 changes: 96 additions & 0 deletions test/integration_tests/python/test_propagation.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,102 @@ def get_user_in_perms(perms, uid):
user = get_user_in_perms(perms, user_id)
assert r.ok and user is None

# Test group permission propagation
def test_add_and_remove_user_group_permission(data_builder, as_admin):
"""
Tests:
- changing permissions at a group level with flag triggers propagation
- additive change to list propagates properly
- change to list propagates properly
- removal from list propagates properly
"""
def get_user_in_perms(perms, uid):
for perm in perms:
if perm['_id'] == uid:
return perm
return None

group = data_builder.create_group()
project = data_builder.create_project()
session = data_builder.create_session()
acquisition = data_builder.create_acquisition()

user_id = 'propagation@user.com'

# Add user to group permissions
payload = {'_id': user_id, 'access': 'admin'}
r = as_admin.post('/groups/' + group + '/permissions', json=payload, params={'propagate': 'true'})
assert r.ok

r = as_admin.get('/groups/' + group)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user

r = as_admin.get('/projects/' + project)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.json()['group'] == group
assert r.ok and user

r = as_admin.get('/sessions/' + session)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user

r = as_admin.get('/acquisitions/' + acquisition)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user

# Modify user permissions
payload = {'access': 'rw', '_id': user_id}
r = as_admin.put('/groups/' + group + '/permissions/' + user_id, json=payload, params={'propagate': 'true'})
assert r.ok

r = as_admin.get('/groups/' + group)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user and user['access'] == 'rw'

r = as_admin.get('/projects/' + project)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user and user['access'] == 'rw'

r = as_admin.get('/sessions/' + session)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user and user['access'] == 'rw'

r = as_admin.get('/acquisitions/' + acquisition)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user and user['access'] == 'rw'

# Remove user from project permissions
r = as_admin.delete('/groups/' + group + '/permissions/' + user_id, json=payload, params={'propagate': 'true'})
assert r.ok

r = as_admin.get('/groups/' + group)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user is None

r = as_admin.get('/projects/' + project)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user is None

r = as_admin.get('/sessions/' + session)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user is None

r = as_admin.get('/acquisitions/' + acquisition)
perms = r.json()['permissions']
user = get_user_in_perms(perms, user_id)
assert r.ok and user is None

# Test tag pool renaming and deletion
def test_add_rename_remove_group_tag(data_builder, as_admin):
Expand Down