Skip to content

Commit

Permalink
Merge remote-tracking branch 'okfn/master' into 981-extend-datastore-…
Browse files Browse the repository at this point in the history
…create
  • Loading branch information
domoritz committed Aug 5, 2013
2 parents 955e422 + d8fcedf commit 1ef8891
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 71 deletions.
10 changes: 8 additions & 2 deletions ckan/controllers/package.py
Expand Up @@ -264,8 +264,14 @@ def pager_url(q=None, page=None):
c.page = h.Page(collection=[])
c.search_facets_limits = {}
for facet in c.search_facets.keys():
limit = int(request.params.get('_%s_limit' % facet,
g.facets_default_number))
try:
limit = int(request.params.get('_%s_limit' % facet,
g.facets_default_number))
except ValueError:
abort(400, _('Parameter "{parameter_name}" is not '
'an integer').format(
parameter_name='_%s_limit' % facet
))
c.search_facets_limits[facet] = limit

maintain.deprecate_context_item(
Expand Down
78 changes: 73 additions & 5 deletions ckan/logic/__init__.py
@@ -1,7 +1,7 @@
import functools
import logging
import types
import re
import sys

import formencode.validators

Expand Down Expand Up @@ -194,8 +194,18 @@ def flatten_to_string_key(dict):


def check_access(action, context, data_dict=None):
user = context.get('user')
action = new_authz.clean_action_name(action)

# Auth Auditing. We remove this call from the __auth_audit stack to show
# we have called the auth function
try:
audit = context.get('__auth_audit', [])[-1]
except IndexError:
audit = ''
if audit and audit[0] == action:
context['__auth_audit'].pop()

user = context.get('user')
log.debug('check access - user %r, action %s' % (user, action))

if action:
Expand Down Expand Up @@ -281,13 +291,17 @@ def get_action(action):
module = getattr(module, part)
for k, v in module.__dict__.items():
if not k.startswith('_'):
# Only load functions from the action module.
if isinstance(v, types.FunctionType):
# Only load functions from the action module or already
# replaced functions.
if (hasattr(v, '__call__')
and (v.__module__ == module_path
or hasattr(v, '__replaced'))):
k = new_authz.clean_action_name(k)
_actions[k] = v

# Whitelist all actions defined in logic/action/get.py as
# being side-effect free.
# FIXME This looks wrong should it be an 'or' not 'and'
v.side_effect_free = getattr(v, 'side_effect_free', True)\
and action_module_name == 'get'

Expand All @@ -306,6 +320,9 @@ def get_action(action):
)
log.debug('Auth function %r was inserted', plugin.name)
resolved_action_plugins[name] = plugin.name
# Extensions are exempted from the auth audit for now
# This needs to be resolved later
auth_function.auth_audit_exempt = True
fetched_actions[name] = auth_function
# Use the updated ones in preference to the originals.
_actions.update(fetched_actions)
Expand All @@ -326,9 +343,37 @@ def wrapped(context=None, data_dict=None, **kw):
except TypeError:
# c not registered
pass
return _action(context, data_dict, **kw)

# Auth Auditing
# store this action name in the auth audit so we can see if
# check access was called on the function we store the id of
# the action incase the action is wrapped inside an action
# of the same name. this happens in the datastore
context.setdefault('__auth_audit', [])
context['__auth_audit'].append((action_name, id(_action)))

# check_access(action_name, context, data_dict=None)
result = _action(context, data_dict, **kw)
try:
audit = context['__auth_audit'][-1]
if audit[0] == action_name and audit[1] == id(_action):
if action_name not in new_authz.auth_functions_list():
log.debug('No auth function for %s' % action_name)
elif not getattr(_action, 'auth_audit_exempt', False):
raise Exception('Action Auth Audit: %s' % action_name)
# remove from audit stack
context['__auth_audit'].pop()
except IndexError:
pass
return result
return wrapped

# If we have been called multiple times for example during tests then
# we need to make sure that we do not rewrap the actions.
if hasattr(_action, '__replaced'):
_actions[action_name] = _action.__replaced
continue

fn = make_wrapped(_action, action_name)
# we need to mirror the docstring
fn.__doc__ = _action.__doc__
Expand All @@ -337,6 +382,22 @@ def wrapped(context=None, data_dict=None, **kw):
fn.side_effect_free = True
_actions[action_name] = fn


def replaced_action(action_name):
def warn(context, data_dict):
log.critical('Action `%s` is being called directly '
'all action calls should be accessed via '
'logic.get_action' % action_name)
return get_action(action_name)(context, data_dict)
return warn

# Store our wrapped function so it is available. This is to prevent
# rewrapping of actions
module = sys.modules[_action.__module__]
r = replaced_action(action_name)
r.__replaced = fn
module.__dict__[action_name] = r

return _actions.get(action)


Expand Down Expand Up @@ -400,6 +461,13 @@ def wrapper(context, data_dict):
return wrapper


def auth_audit_exempt(action):
''' Dirty hack to stop auth audit being done '''
@functools.wraps(action)
def wrapper(context, data_dict):
return action(context, data_dict)
wrapper.auth_audit_exempt = True
return wrapper

class UnknownValidator(Exception):
pass
Expand Down
1 change: 1 addition & 0 deletions ckan/logic/action/create.py
Expand Up @@ -703,6 +703,7 @@ def organization_create(context, data_dict):
return _group_or_org_create(context, data_dict, is_org=True)


@logic.auth_audit_exempt
def rating_create(context, data_dict):
'''Rate a dataset (package).
Expand Down
18 changes: 9 additions & 9 deletions ckan/logic/action/get.py
Expand Up @@ -826,6 +826,8 @@ def resource_status_show(context, data_dict):

return result_list


@logic.auth_audit_exempt
def revision_show(context, data_dict):
'''Return the details of a revision.
Expand Down Expand Up @@ -1008,7 +1010,7 @@ def user_show(context, data_dict):

revisions_list = []
for revision in revisions_q.limit(20).all():
revision_dict = revision_show(context,{'id':revision.id})
revision_dict = logic.get_action('revision_show')(context,{'id':revision.id})
revision_dict['state'] = revision.state
revisions_list.append(revision_dict)
user_dict['activity'] = revisions_list
Expand All @@ -1020,7 +1022,7 @@ def user_show(context, data_dict):

for dataset in dataset_q:
try:
dataset_dict = package_show(context, {'id': dataset.id})
dataset_dict = logic.get_action('package_show')(context, {'id': dataset.id})
except logic.NotAuthorized:
continue
user_dict['datasets'].append(dataset_dict)
Expand Down Expand Up @@ -2554,9 +2556,10 @@ def display_name(followee):

# Get the followed objects.
# TODO: Catch exceptions raised by these *_followee_list() functions?
# FIXME should we be changing the context like this it seems dangerous
followee_dicts = []
context['skip_validation'] = True
context['skip_authorization'] = True
context['ignore_auth'] = True
for followee_list_function, followee_type in (
(user_followee_list, 'user'),
(dataset_followee_list, 'dataset'),
Expand Down Expand Up @@ -2591,8 +2594,7 @@ def user_followee_list(context, data_dict):
:rtype: list of dictionaries
'''
if not context.get('skip_authorization'):
_check_access('user_followee_list', context, data_dict)
_check_access('user_followee_list', context, data_dict)

if not context.get('skip_validation'):
schema = context.get('schema') or (
Expand Down Expand Up @@ -2622,8 +2624,7 @@ def dataset_followee_list(context, data_dict):
:rtype: list of dictionaries
'''
if not context.get('skip_authorization'):
_check_access('dataset_followee_list', context, data_dict)
_check_access('dataset_followee_list', context, data_dict)

if not context.get('skip_validation'):
schema = context.get('schema') or (
Expand Down Expand Up @@ -2654,8 +2655,7 @@ def group_followee_list(context, data_dict):
:rtype: list of dictionaries
'''
if not context.get('skip_authorization'):
_check_access('group_followee_list', context, data_dict)
_check_access('group_followee_list', context, data_dict)

if not context.get('skip_validation'):
schema = context.get('schema',
Expand Down
3 changes: 2 additions & 1 deletion ckan/logic/action/update.py
Expand Up @@ -768,8 +768,9 @@ def term_translation_update_many(context, data_dict):

context['defer_commit'] = True

action = _get_action('term_translation_update')
for num, row in enumerate(data_dict['data']):
term_translation_update(context, row)
action(context, row)

model.Session.commit()

Expand Down
3 changes: 3 additions & 0 deletions ckan/logic/auth/get.py
Expand Up @@ -254,14 +254,17 @@ def followee_list(context, data_dict):
return _followee_list(context, data_dict)


@logic.auth_audit_exempt
def user_followee_list(context, data_dict):
return _followee_list(context, data_dict)


@logic.auth_audit_exempt
def dataset_followee_list(context, data_dict):
return _followee_list(context, data_dict)


@logic.auth_audit_exempt
def group_followee_list(context, data_dict):
return _followee_list(context, data_dict)

Expand Down

0 comments on commit 1ef8891

Please sign in to comment.