Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with missing auth_user_obj #7109

Open
knudmoeller opened this issue Sep 28, 2022 · 0 comments
Open

Problems with missing auth_user_obj #7109

knudmoeller opened this issue Sep 28, 2022 · 0 comments
Assignees

Comments

@knudmoeller
Copy link
Contributor

CKAN version

2.9.5

Describe the bug

TLDR: context['auth_user_obj'] is not always defined, which can lead to unwanted exceptions when calling ckan.authz.py.auth_is_loggedin_user(), especially when implementing IAuthFunctions in a plugin. Years ago, before Flask, there was a PR with a solution for this that was never merged. Now with Flask, this solution doesn't work under all circumstances anymore.


This is a follow-up to the open issues #4183 and #4097. The main point of both was that ckan.authz.py.auth_is_loggedin_user() would fail if auth_user_obj was not defined in the context. This was still in the Pylons-era, before Flask.

ckan/ckan/authz.py

Lines 173 to 174 in bc4f8df

if not getattr(auth_function, 'auth_allow_anonymous_access', False) \
and not context.get('auth_user_obj'):

The proposed solution was to check ckan.authz.py.auth_is_loggedin_user() instead of looking for the auth_user_obj. The implementation would have looked like this:

logged_in = context.get('auth_user_obj') or auth_is_loggedin_user()
if not getattr(auth_function, 'auth_allow_anonymous_access', False) \
    and not logged_in:

This was actually implemented in PR #4222 by @amercader, but was then somehow never merged.

I would like to propose a new PR with this change. However, now I'm running into the problem that this code fails when run from the context of a test, rather than within a running application. This is because apparently there is no Flask application context. The test looks like this:

    def test_technical_group_excluded_for_regular(self, app):
>       factories.Organization(name='regular')
        ...
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:46: in __call__
    return cls.create(**kwargs)
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:564: in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:501: in _generate
    return step.build()
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/builder.py:276: in build
    instance = self.factory_meta.instantiate(
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:315: in instantiate
    return self.factory._create(model, *args, **kwargs)
/usr/lib/ckan/default/src/ckan/ckan/tests/factories.py:311: in _create
    group_dict = helpers.call_action(
/usr/lib/ckan/default/src/ckan/ckan/tests/helpers.py:129: in call_action
    return logic.get_action(action_name)(context=context, data_dict=kwargs)
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/create.py:931: in organization_create
    return _group_or_org_create(context, data_dict, is_org=True)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/create.py:799: in _group_or_org_create
    else _get_action(action)(context, {'id': group.id})
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
ckanext/berlinauth/action/get.py:76: in organization_show
    group_dict = ckanget.organization_show(context, data_dict)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:1302: in organization_show
    return _group_or_org_show(context, data_dict, is_org=True)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:1219: in _group_or_org_show
    group_dict['num_followers'] = logic.get_action('group_follower_count')(
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:2754: in group_follower_count
    _check_access('group_follower_count', context, data_dict)
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:309: in check_access
    logic_authorization = authz.is_authorized(action, context,
/usr/lib/ckan/default/src/ckan/ckan/authz.py:217: in is_authorized
    logged_in = context.get('auth_user_obj') or auth_is_loggedin_user()
/usr/lib/ckan/default/src/ckan/ckan/authz.py:537: in auth_is_loggedin_user
    context_user = g.user
/usr/lib/ckan/default/lib/python3.8/site-packages/werkzeug/local.py:347: in __getattr__
    return getattr(self._get_current_object(), name)
/usr/lib/ckan/default/lib/python3.8/site-packages/werkzeug/local.py:347: in __getattr__
    return getattr(self._get_current_object(), name)
/usr/lib/ckan/default/lib/python3.8/site-packages/werkzeug/local.py:306: in _get_current_object
    return self.__local()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

name = 'g'

    def _lookup_app_object(name):
        top = _app_ctx_stack.top
        if top is None:
>           raise RuntimeError(_app_ctx_err_msg)
E           RuntimeError: Working outside of application context.
E           
E           This typically means that you attempted to use functionality that needed
E           to interface with the current application object in some way. To solve
E           this, set up an application context with app.app_context().  See the
E           documentation for more information.

/usr/lib/ckan/default/lib/python3.8/site-packages/flask/globals.py:45: RuntimeError

I have tried to follow the suggestion in the error message and wrapped the relevant calls in the test in a with app.flask_app.app_context():, but now I get an AttributeError: '_Globals' object has no attribute 'user':

    def test_technical_group_excluded_for_regular(self, app):
        with app.flask_app.app_context():
>           factories.Organization(name='regular')

ckanext/berlinauth/tests/test_action_get.py:51: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:46: in __call__
    return cls.create(**kwargs)
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:564: in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:501: in _generate
    return step.build()
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/builder.py:276: in build
    instance = self.factory_meta.instantiate(
/usr/lib/ckan/default/lib/python3.8/site-packages/factory/base.py:315: in instantiate
    return self.factory._create(model, *args, **kwargs)
/usr/lib/ckan/default/src/ckan/ckan/tests/factories.py:311: in _create
    group_dict = helpers.call_action(
/usr/lib/ckan/default/src/ckan/ckan/tests/helpers.py:129: in call_action
    return logic.get_action(action_name)(context=context, data_dict=kwargs)
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/create.py:931: in organization_create
    return _group_or_org_create(context, data_dict, is_org=True)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/create.py:799: in _group_or_org_create
    else _get_action(action)(context, {'id': group.id})
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
ckanext/berlinauth/action/get.py:76: in organization_show
    group_dict = ckanget.organization_show(context, data_dict)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:1302: in organization_show
    return _group_or_org_show(context, data_dict, is_org=True)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:1219: in _group_or_org_show
    group_dict['num_followers'] = logic.get_action('group_follower_count')(
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:504: in wrapped
    result = _action(context, data_dict, **kw)
/usr/lib/ckan/default/src/ckan/ckan/logic/action/get.py:2757: in group_follower_count
    _check_access('group_follower_count', context, data_dict)
/usr/lib/ckan/default/src/ckan/ckan/logic/__init__.py:309: in check_access
    logic_authorization = authz.is_authorized(action, context,
/usr/lib/ckan/default/src/ckan/ckan/authz.py:220: in is_authorized
    logged_in = context.get('auth_user_obj') or auth_is_loggedin_user()
/usr/lib/ckan/default/src/ckan/ckan/authz.py:542: in auth_is_loggedin_user
    context_user = g.user
/usr/lib/ckan/default/lib/python3.8/site-packages/werkzeug/local.py:347: in __getattr__
    return getattr(self._get_current_object(), name)
/usr/lib/ckan/default/lib/python3.8/site-packages/werkzeug/local.py:347: in __getattr__
    return getattr(self._get_current_object(), name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ckan.config.middleware.flask_app.CKAN_AppCtxGlobals object at 0x7fc10c063790>, name = 'user'

    def __getattr__(self, name):
        '''
        If flask.g doesn't have attribute `name`, fall back to CKAN's
        app_globals object.
        If the key is also not found in there, an AttributeError will be raised
        '''
>       return getattr(app_globals.app_globals, name)
E       AttributeError: '_Globals' object has no attribute 'user'

I'm a bit conflicted about this whole issue report, because I'm not sure if the main problem here is the missing auth_user_obj, or the missing/incomplete application context, or both.

If necessary, I can try to provide a minimal plugin that illustrates this problem, but I'm hoping the issue can be discussed without this.

Steps to reproduce
Steps to reproduce the behavior:

Expected behavior
A clear and concise description of what you expected to happen.

Additional details
If possible, please provide the full stack trace of the error raised, or add screenshots to help explain your problem.

@amercader amercader self-assigned this Sep 29, 2022
knudmoeller added a commit to berlinonline/ckanext-berlinauth that referenced this issue Oct 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants