python-social-auth / social-app-django

Python Social Auth - Application - Django
BSD 3-Clause "New" or "Revised" License
2.01k stars 375 forks source link

[ORCID] No last name triggers AttributeError #355

Closed wiwski closed 4 months ago

wiwski commented 2 years ago

Expected behaviour

I should be able to log in with my ORCID account as documented here.

Actual behaviour

After ORCID log in & consent, in the redirection process, I get an AttributeError. It happens when getting user details from ORCID response.

What are the steps to reproduce this issue?

Input clear steps to reproduce the issue for a maintainer.

  1. Create an ORCID account with no last name.
  2. Add <a href="{% url "social:begin" "orcid-sandbox" %}">{% translate 'Sign in with ORCID' %}</a> to a template
  3. Click on the link.
  4. Sign in to ORCID Account & grant access to the app.
  5. Redirection appears, then see the bug.

Any logs, error output, etc?

See error log below. Error happens on this line : last_name = name.get('family-name', {}).get('value', '')

name is a dict :

 {'created-date': {'value': 1633016508754}, 'last-modified-date': {'value': 1633016508754}, 'given-names': {'value': 'Witold'}, 'family-name': None, 'credit-name': None, 'source': None, 'visibility': 'PUBLIC', 'path': '0000-0003-3541-9859'} 
Internal Server Error: //complete/orcid-sandbox/
Traceback (most recent call last):
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/views/decorators/cache.py", line 56, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_django/utils.py", line 46, in wrapper
    return func(request, backend, *args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_django/views.py", line 31, in complete
    return do_complete(request.backend, _do_login, user=request.user,
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/actions.py", line 45, in do_complete
    user = backend.complete(user=user, *args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/base.py", line 40, in complete
    return self.auth_complete(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/utils.py", line 248, in wrapper
    return func(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/oauth.py", line 391, in auth_complete
    return self.do_auth(response['access_token'], response=response,
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/utils.py", line 248, in wrapper
    return func(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/oauth.py", line 403, in do_auth
    return self.strategy.authenticate(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_django/strategy.py", line 105, in authenticate
    return authenticate(*args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/views/decorators/debug.py", line 42, in sensitive_variables_wrapper
    return func(*func_args, **func_kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/django/contrib/auth/__init__.py", line 76, in authenticate
    user = backend.authenticate(request, **credentials)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/base.py", line 80, in authenticate
    return self.pipeline(pipeline, *args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/base.py", line 83, in pipeline
    out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs)
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/base.py", line 113, in run_pipeline
    result = func(*args, **out) or {}
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/pipeline/social_auth.py", line 5, in social_details
    return {'details': dict(backend.get_user_details(response), **details)}
  File "/home/witold/.local/share/virtualenvs/euphrosyne-IL9ecKbp/lib/python3.9/site-packages/social_core/backends/orcid.py", line 79, in get_user_details
    last_name = name.get('family-name', {}).get('value', '')
AttributeError: 'NoneType' object has no attribute 'get'
paloha commented 1 year ago

I got the same error. I investigated a bit and the problem is that the line 65:

person = response.get("person")

stores the following json in the person variable:

{'created-date': {'value': 1684137584077},
 'credit-name': None,
 'family-name': None,
 'given-names': {'value': 'John'},
 'last-modified-date': {'value': 1684137584077},
 'path': '0000-0000-0000-0000',
 'source': None,
 'visibility': 'PUBLIC'}

There, the 'family_name' key is present, however its value can be None. And by calling the code on line 78:

last_name = name.get("family-name", {}).get("value", "")

the name.get("family-name", {}) evaluates to None and None obviously does not have a get() method. Hence the error.

In ORCID it is mandatory to fill in your first name, thus the given-names dict should always have a value key, however, it is not mandatory to fill in your last name, so the implementation should probably be something like this:

if name.get('family-name', None) is not None: 
    last_name = name.get('family-name').get('value')

In case the user did not fill in their family name, the line 63:

fullname = first_name = last_name = email = username = ""

already sets last_name to a default "".

I might submit a PR if I find time in the near future. In case somebody is faster I will not be mad :)

nikoder commented 4 months ago

This should be resolved on social-core master, as of commit 95316b0914386af59d8649917c373a594f1766de (see the above PR for details).

By installing a version of social-core (package name social-auth-core) which includes that commit in your environment, social-auth-app-django should no longer stumble in this case.