paperless-ngx / paperless-ngx

A community-supported supercharged version of paperless: scan, index and archive all your physical documents
https://docs.paperless-ngx.com
GNU General Public License v3.0
19.21k stars 1.05k forks source link

[BUG] OIDC: signup fails if no email server setup #5870

Closed noantiq closed 6 months ago

noantiq commented 6 months ago

Description

When setting up OIDC I noticed that the default settings concerning user signup contradict each other which results in an exception that leads to paperless needing a restart. As seen below the default settings disallow signups in general but allow social signups. 5476CC3D-6940-4A84-BCF0-8BE0D049E885

When setting up OIDC signups and leaving the settings as is the signup process is started as expected but fails at the final step.

IMG_1370 IMG_1371

Afterwards, when trying to log in with a pre-existing account paperless is not loading. IMG_1372

After inspecting the logs I can see that paperless failed during the signup since an exception occurred.

The docs do not mention that you have to explicitly allow signups in general - even though it might make sense.

What I suggest should happen:

Anyway, I know that the integration of social accounts came in very recently and therefore I expected some minor problems like this, but all in all it works really well so far. Thank you and keep up the excellent work!

Steps to reproduce

  1. Set up social login according to the documentation - only specifying the PAPERLESS_APPS and PAPERLESS_SOCIALACCOUNT_PROVIDERS info.
  2. Try to login using a social (oidc) account.

Webserver logs


paperless         | [2024-02-23 09:22:50,260] [ERROR] [django.request] Internal Server Error: /paperless/accounts/social/signup/
paperless         | Traceback (most recent call last):
paperless         |   File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 534, in thread_handler
paperless         |     raise exc_info[1]
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 42, in inner
paperless         |     response = await get_response(request)
paperless         |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 534, in thread_handler
paperless         |     raise exc_info[1]
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
paperless         |     response = await wrapped_callback(
paperless         |                ^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 479, in __call__
paperless         |     ret: _R = await loop.run_in_executor(
paperless         |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py", line 40, in run
paperless         |     result = self.fn(*self.args, **self.kwargs)
paperless         |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 538, in thread_handler
paperless         |     return func(*args, **kwargs)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 104, in view
paperless         |     return self.dispatch(request, *args, **kwargs)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/socialaccount/views.py", line 45, in dispatch
paperless         |     return super(SignupView, self).dispatch(request, *args, **kwargs)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/views.py", line 95, in dispatch
paperless         |     response = super(RedirectAuthenticatedUserMixin, self).dispatch(
paperless         |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/views.py", line 227, in dispatch
paperless         |     return super(CloseableSignupMixin, self).dispatch(request, *args, **kwargs)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 143, in dispatch
paperless         |     return handler(request, *args, **kwargs)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/views.py", line 123, in post
paperless         |     response = self.form_valid(form)
paperless         |                ^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/socialaccount/views.py", line 61, in form_valid
paperless         |     resp = helpers.complete_social_signup(self.request, self.sociallogin)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/socialaccount/helpers.py", line 244, in complete_social_signup
paperless         |     return complete_signup(
paperless         |            ^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/utils.py", line 241, in complete_signup
paperless         |     return perform_login(
paperless         |            ^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/utils.py", line 166, in perform_login
paperless         |     return _perform_login(request, login)
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/utils.py", line 176, in _perform_login
paperless         |     response = adapter.pre_login(request, login.user, **hook_kwargs)
paperless         |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/adapter.py", line 461, in pre_login
paperless         |     send_email_confirmation(request, user, signup=signup, email=email)
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/utils.py", line 399, in send_email_confirmation
paperless         |     email_address.send_confirmation(request, signup=signup)
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/models.py", line 93, in send_confirmation
paperless         |     confirmation.send(request, signup=signup)
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/models.py", line 126, in send
paperless         |     get_adapter().send_confirmation_mail(request, self, signup)
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/adapter.py", line 641, in send_confirmation_mail
paperless         |     self.send_mail(email_template, emailconfirmation.email_address.email, ctx)
paperless         |   File "/usr/local/lib/python3.11/site-packages/allauth/account/adapter.py", line 186, in send_mail
paperless         |     msg.send()
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/core/mail/message.py", line 298, in send
paperless         |     return self.get_connection(fail_silently).send_messages([self])
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/core/mail/backends/smtp.py", line 127, in send_messages
paperless         |     new_conn_created = self.open()
paperless         |                        ^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/site-packages/django/core/mail/backends/smtp.py", line 85, in open
paperless         |     self.connection = self.connection_class(
paperless         |                       ^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/smtplib.py", line 255, in __init__
paperless         |     (code, msg) = self.connect(host, port)
paperless         |                   ^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/smtplib.py", line 341, in connect
paperless         |     self.sock = self._get_socket(host, port, self.timeout)
paperless         |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/smtplib.py", line 312, in _get_socket
paperless         |     return socket.create_connection((host, port), timeout,
paperless         |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
paperless         |   File "/usr/local/lib/python3.11/socket.py", line 851, in create_connection
paperless         |     raise exceptions[0]
paperless         |   File "/usr/local/lib/python3.11/socket.py", line 836, in create_connection
paperless         |     sock.connect(sa)
paperless         | OSError: [Errno 99] Cannot assign requested address

Browser logs

No response

Paperless-ngx version

latest - 2.5.3

Host OS

should be irrelevant but RasPi OS arm

Installation method

Docker - official image

Browser

No response

Configuration changes

No response

Other

No response

Please confirm the following

stumpylog commented 6 months ago

Given that's allauth crashing, this seems better reported to them. There's not even a place there where paperless code is involved.

Also, OSError: [Errno 99] Cannot assign requested is just a low level network problem that is probably something about your own system.

noantiq commented 6 months ago

Hi @stumpylog thanks for the clarification. I am obviously not aware of how exactly you interact with django-allauth and where or how much paperless code is involved but the issue is not (only) about the error message that was printed to the logs and I think some if not all of my suggestions are still applicable.

I would assume that the two config options are handled by paperless, or am I wrong here? If so you could mitigate this exception altogether by not starting the signup flow at all when the value for PAPERLESS_ALLOW_SIGNUPS is set to False or by changing the logic of these flags (as suggested above).

Again, I do not know much about django and I did not look through the paperless code but when I use a library and in some scenarios that library might throw an exception effectively making my app unusable until it’s restarted I either assure that these scenarios cannot occur or at least catch the exception and show a meaningful message in the logs for an admin to check and preferably in the UI for the user to get a sense of what failed. So no matter if allauth crashed this could be handled by paperless. At least that’s my understanding, please correct me if I got something wrong.

My last suggestion was to add a remark to the docs, I think that should be possible even if nothing is changed code wise and regardless of why the error occurs in this scenario.

shamoon commented 6 months ago

You do not need PAPERLESS_ACCOUNT_ALLOW_SIGNUPS enabled. I just checked this again and signed up for an account with only:

PAPERLESS_APPS="allauth.socialaccount.providers.github,allauth.socialaccount.providers.openid_connect"
PAPERLESS_SOCIALACCOUNT_PROVIDERS='{"github": {"APPS": [{"provider_id": "github","name": "Github New","client_id": "***","secret": "***"}]}}'

The error above seems to be an email thing (and doesnt mention PAPERLESS_ACCOUNT_ALLOW_SIGNUPS?). I also did the above test without any email server setup so either theres a bug in allauth (please raise the issue there as noted, see https://github.com/pennersr/django-allauth/issues ) or you just have it misconfigured.

Feel free to add more if we're missing something here, otherwise I'll close this out.

noantiq commented 6 months ago

Hi @shamoon thank you for your input. Based on your pointers I tried reproducing the crash with a clean install and investigated a bit further. I was able to reproduce it but you are correct, the PAPERLESS_ACCOUNT_ALLOW_SIGNUPS option has nothing to do with it. It simply worked when I enabled that option and restarted Paperless and thus I assumed there must be a causal relationship between these two, but the restart part actually let me log in without an error.

Nonetheless the crash on signup consistently occurs in two situations:

In both of these cases the Ul successfully forces you to enter a valid email address that is not in use already (see screenshot below), but even when you then change the email address in the Ul, after you hit that "Sign up" button you are greeted with the server error screen and log error message I described above. Apparently (guessing from the experimenting and the log output i sent) the “old” email address that was provided by the OICD provider is used to send out a confirmation mail (even when no mail server is configured).

After restarting Paperless I was able to log in using OICD and the created profile in paperless had the changed valid email address connected.

IMG_1384

shamoon commented 6 months ago

I see that we need probably need a way to set ACCOUNT_EMAIL_VERIFICATION. Maybe more like an enhancement vs a bug but agree its unexpected

github-actions[bot] commented 5 months ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new discussion or issue for related concerns. See our contributing guidelines for more details.