diff --git a/attract/application/__init__.py b/attract/application/__init__.py index e84955df..886435e2 100644 --- a/attract/application/__init__.py +++ b/attract/application/__init__.py @@ -1,10 +1,10 @@ import os +import json from eve import Eve # import random # import string -import json from eve.auth import TokenAuth from eve.auth import BasicAuth @@ -13,12 +13,20 @@ from eve.methods.post import post_internal from bson import ObjectId from flask import g -from flask import abort from flask import request +from pre_hooks import pre_GET +from pre_hooks import pre_PUT +from pre_hooks import pre_PATCH +from pre_hooks import pre_POST +from pre_hooks import pre_DELETE +from pre_hooks import check_permissions +from pre_hooks import compute_permissions + from datetime import datetime from datetime import timedelta + RFC1123_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' @@ -100,217 +108,6 @@ def validate_token(): return token_data -def global_validation(): - setattr(g, 'token_data', validate_token()) - setattr(g, 'validate', validate(g.get('token_data')['token'])) - check_permissions(g.get('token_data')['user']) - - -def permissions_lookup(action, lookup): - type_world_permissions = g.get('type_world_permissions') - type_owner_permissions = g.get('type_owner_permissions') - node_types = [] - # Get all node_types allowed by world: - for per in type_world_permissions: - if action in type_world_permissions[per]: - node_types.append(str(per)) - # Get all nodes with node_type allowed by owner if user == owner - owner_lookup = [] - for per in type_owner_permissions: - if action in type_owner_permissions[per]: - if action not in type_world_permissions[per]: - # If one of the following is true - # If node_type==node_type and user==user - owner_lookup.append( - {'$and': [{'node_type': str(per)}, - {'user': str(g.get('token_data')['user'])}]}) - lookup['$or'] = [{'node_type': {'$in': node_types}}] - if len(owner_lookup) > 0: - lookup['$or'].append({'$or': owner_lookup}) - return lookup - - -def pre_GET(request, lookup): - # Only get allowed documents - global_validation() - # print ("Get") - # print ("Owner: {0}".format(g.get('owner_permissions'))) - # print ("World: {0}".format(g.get('world_permissions'))) - action = 'GET' - if 'token_type' not in lookup and '_id' not in request.view_args: - # Is quering for all nodes (mixed types) - lookup = permissions_lookup(action, lookup) - else: - # Is quering for one specific node - if action not in g.get('world_permissions') and \ - action not in g.get('groups_permissions'): - lookup['user'] = g.get('token_data')['user'] - # token_data = validate_token() - # validate(token_data['token']) - - # lookup["userr"] = "user" - # print ("Lookup") - # print (lookup) - - -def pre_PUT(request, lookup): - # Only Update allowed documents - global_validation() - # print ("Put") - # print ("Owner: {0}".format(g.get('owner_permissions'))) - # print ("World: {0}".format(g.get('world_permissions'))) - action = 'UPDATE' - if 'token_type' not in lookup and '_id' not in request.view_args: - # Is updating all nodes (mixed types) - lookup = permissions_lookup(action, lookup) - else: - # Is updating one specific node - if action not in g.get('world_permissions') and \ - action not in g.get('groups_permissions'): - lookup['user'] = g.get('token_data')['user'] - - # print ("Lookup") - # print (lookup) - - -def pre_PATCH(request, lookup): - print ("Patch") - - -def pre_POST(request): - # Only Post allowed documents - global_validation() - # print ("Post") - # print ("World: {0}".format(g.get('world_permissions'))) - # print ("Group: {0}".format(g.get('groups_permissions'))) - action = 'POST' - print (g.get('type_groups_permissions')) - # Is quering for one specific node - if action not in g.get('world_permissions') and \ - action not in g.get('groups_permissions'): - abort(403) - - -def pre_DELETE(request, lookup): - # Only Delete allowed documents - global_validation() - type_world_permissions = g.get('type_world_permissions') - type_owner_permissions = g.get('type_owner_permissions') - type_groups_permissions = g.get('type_groups_permissions') - # print ("Delete") - print ("Owner: {0}".format(type_owner_permissions)) - print ("World: {0}".format(type_world_permissions)) - print ("Groups: {0}".format(type_groups_permissions)) - action = 'DELETE' - - if '_id' in lookup: - nodes = app.data.driver.db['nodes'] - dbnode = nodes.find_one({'_id': ObjectId(lookup['_id'])}) - # print (dbnode.count()) - node_type = dbnode['node_type'] - if g.get('token_data')['user'] == dbnode['user']: - owner = True - else: - owner = False - if action not in type_world_permissions[node_type] and \ - action not in type_groups_permissions[node_type]: - if action not in type_owner_permissions[node_type]: - print ("Abort1") - abort(403) - else: - if not owner: - print ("Abort2") - abort(403) - else: - print ("Abort3") - abort(403) - - -def check_permissions(user): - node_type = None - dbnode = None - owner_permissions = [] - world_permissions = [] - groups_permissions = [] - groups = app.data.driver.db['groups'] - users = app.data.driver.db['users'] - owner_group = groups.find_one({'name': 'owner'}) - world_group = groups.find_one({'name': 'world'}) - user_data = users.find_one({'_id': ObjectId(user)}) - # Entry point should be nodes - entry_point = request.path.split("/")[1] - if entry_point != 'nodes': - return - # If is requesting a specific node - try: - uuid = request.path.split("/")[2] - nodes = app.data.driver.db['nodes'] - lookup = {'_id': ObjectId(uuid)} - dbnode = nodes.find_one(lookup) - except IndexError: - pass - if dbnode: - node_type = str(dbnode['node_type']) - - json_data = None - try: - json_data = json.loads(request.data) - except ValueError: - pass - if not node_type and json_data: - if 'node_type' in json_data: - node_type = json_data['node_type'] - - # Extract query lookup - # which node_type is asking for? - for arg in request.args: - if arg == 'where': - try: - where = json.loads(request.args[arg]) - except ValueError: - raise - if where.get('node_type'): - node_type = where.get('node_type') - break - - # Get and store permissions for that node_type - type_owner_permissions = {} - type_world_permissions = {} - type_groups_permissions = {} - - for per in owner_group['permissions']: - type_owner_permissions[per['node_type']] = per['permissions'] - if str(per['node_type']) == node_type: - owner_permissions = per['permissions'] - - for per in world_group['permissions']: - type_world_permissions[per['node_type']] = per['permissions'] - if str(per['node_type']) == node_type: - world_permissions = per['permissions'] - - # Adding empty permissions - if per['node_type'] not in type_groups_permissions: - type_groups_permissions[per['node_type']] = [] - - groups_data = user_data.get('groups') - if groups_data: - for group in groups_data: - group_data = groups.find_one({'_id': ObjectId(group)}) - for per in group_data['permissions']: - type_groups_permissions[per['node_type']] += \ - per['permissions'] - if str(per['node_type']) == node_type: - groups_permissions = per['permissions'] - - # Store permission properties on global - setattr(g, 'owner_permissions', owner_permissions) - setattr(g, 'world_permissions', world_permissions) - setattr(g, 'groups_permissions', groups_permissions) - setattr(g, 'type_owner_permissions', type_owner_permissions) - setattr(g, 'type_world_permissions', type_world_permissions) - setattr(g, 'type_groups_permissions', type_groups_permissions) - - class TokensAuth(TokenAuth): def check_auth(self, token, allowed_roles, resource, method): @@ -421,11 +218,72 @@ def post_item(entry, data): app = Eve(validator=ValidateCustomFields, auth=CustomTokenAuth) -app.on_pre_GET_nodes += pre_GET -app.on_pre_POST_nodes += pre_POST -app.on_pre_PATCH_nodes += pre_PATCH -app.on_pre_PUT_nodes += pre_PUT -app.on_pre_DELETE_nodes += pre_DELETE + + +def global_validation(): + setattr(g, 'token_data', validate_token()) + setattr(g, 'validate', validate(g.get('token_data')['token'])) + check_permissions(g.get('token_data')['user'], app.data.driver) + + +def pre_GET_nodes(request, lookup): + # Only get allowed documents + global_validation() + # print ("Get") + # print ("Owner: {0}".format(g.get('owner_permissions'))) + # print ("World: {0}".format(g.get('world_permissions'))) + return pre_GET(request, lookup, app.data.driver) + + +def pre_PUT_nodes(request, lookup): + # Only Update allowed documents + global_validation() + # print ("Put") + # print ("Owner: {0}".format(g.get('owner_permissions'))) + # print ("World: {0}".format(g.get('world_permissions'))) + return pre_PUT(request, lookup, app.data.driver) + + +def pre_PATCH_nodes(request): + return pre_PATCH(request, app.data.driver) + + +def pre_POST_nodes(request): + global_validation() + # print ("Post") + # print ("World: {0}".format(g.get('world_permissions'))) + # print ("Group: {0}".format(g.get('groups_permissions'))) + return pre_POST(request, app.data.driver) + + +def pre_DELETE_nodes(request, lookup): + # Only Delete allowed documents + global_validation() + # print ("Delete") + # print ("Owner: {0}".format(type_owner_permissions)) + # print ("World: {0}".format(type_world_permissions)) + # print ("Groups: {0}".format(type_groups_permissions)) + return pre_DELETE(request, lookup, app.data.driver) + + +app.on_pre_GET_nodes += pre_GET_nodes +app.on_pre_POST_nodes += pre_POST_nodes +app.on_pre_PATCH_nodes += pre_PATCH_nodes +app.on_pre_PUT_nodes += pre_PUT_nodes +app.on_pre_DELETE_nodes += pre_DELETE_nodes + + +def post_GET_user(request, payload): + json_data = json.loads(payload.data) + json_data['computed_permissions'] = \ + compute_permissions(json_data['_id'], app.data.driver) + # print (json_data) + payload.data = json.dumps(json_data) + # print (payload.data) + + +app.on_post_GET_users += post_GET_user + # The file_server module needs app to be defined from file_server import file_server