ansible / django-ansible-base

Apache License 2.0
18 stars 49 forks source link

Support modifying groups claim for social auth #640

Closed markafarrell closed 5 days ago

markafarrell commented 2 weeks ago

By default social auth hard codes the groups claim to Group.

In general IDPs use groups for returning the user group membership.

This PR support setting the groups claim field.

It also defaults the users list of groups to an empty list(instead of None) if no group claim is found.

If you attempt to use group mapping currently, you get the following error(if your id_token does not include Group)

Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_django/utils.py", line 49, in wrapper
    return func(request, backend, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_django/views.py", line 31, in complete
    return do_complete(
           ^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/actions.py", line 49, in do_complete
    user = backend.complete(user=user, redirect_name=redirect_name, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/base.py", line 39, in complete
    return self.auth_complete(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/utils.py", line 253, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/oauth.py", line 427, in auth_complete
    return self.do_auth(
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/utils.py", line 253, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/oauth.py", line 440, in do_auth
    return self.strategy.authenticate(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_django/strategy.py", line 104, in authenticate
    return authenticate(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/django/views/decorators/debug.py", line 42, in sensitive_variables_wrapper
    return func(*func_args, **func_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/django/contrib/auth/__init__.py", line 77, in authenticate
    user = backend.authenticate(request, **credentials)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/ansible_base/authentication/backend.py", line 40, in authenticate
    user = authenticator_object.authenticate(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/base.py", line 83, in authenticate
    return self.pipeline(pipeline, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/base.py", line 86, in pipeline
    out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/social_core/backends/base.py", line 118, in run_pipeline
    result = func(*args, **out) or {}
             ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/ansible_base/authentication/social_auth.py", line 194, in create_user_claims_pipeline
    user = update_user_claims(kwargs["user"], backend.database_instance, backend.get_user_groups(extra_groups))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/ansible_base/authentication/utils/claims.py", line 290, in update_user_claims
    results = create_claims(database_authenticator, user.username, authenticator_user.extra_data, groups)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/ansible_base/authentication/utils/claims.py", line 72, in create_claims
    trigger_result = process_groups(trigger, groups, authenticator.pk)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/ansible_base/authentication/utils/claims.py", line 176, in process_groups
    set_of_user_groups = set(groups)
                         ^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable
sonarcloud[bot] commented 5 days ago

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
85.7% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

relrod commented 5 days ago

@markafarrell thanks for this!