I'm using python-social-auth in my Django application for authentication via Facebook.
But when a user tries to login, they have been redirected to the Facebook app page, and they click on the "Cancel" button, the following exception appears:
ERROR 2014-01-03 15:32:15,308 base :: Internal Server Error: /complete/facebook/
Traceback (most recent call last):
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
return view_func(*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/utils.py", line 45, in wrapper
return func(request, backend, *args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/views.py", line 21, in complete
redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/actions.py", line 54, in do_complete
*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/strategies/base.py", line 62, in complete
return self.backend.auth_complete(*args, **kwargs)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 63, in auth_complete
self.process_error(self.data)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 56, in process_error
super(FacebookOAuth2, self).process_error(data)
File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/oauth.py", line 312, in process_error
raise AuthCanceled(self, data.get('error_description', ''))
AuthCanceled: Authentication process canceled
Is the any way to catch it Django?
python-social-auth is a newer, derived version of django-social-auth.
AlexYar's answer can be slightly modified to work with python-social-auth by modify settings.py with following changes:
Add a middleware to handle the SocialAuthException
MIDDLEWARE_CLASSES += (
'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
)
URL to redirect to, when an exception occurred
SOCIAL_AUTH_LOGIN_ERROR_URL = '/'
Note that you also need to set
DEBUG = False
That's all or read http://python-social-auth.readthedocs.org/en/latest/configuration/django.html#exceptions-middleware
you can create a middleware and catch any exceptions,
exception list: https://github.com/omab/python-social-auth/blob/master/social/exceptions.py
in this case your AuthCanceled Exception.
middleware.py
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from django.shortcuts import HttpResponse
from social import exceptions as social_exceptions
class SocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if hasattr(social_exceptions, 'AuthCanceled'):
return HttpResponse("I'm the Pony %s" % exception)
else:
raise exception
settings.py
MIDDLEWARE_CLASSES = (
.....
'pat_to_middleware.SocialAuthExceptionMiddleware',
)
This is slight modification of #Nicolas answer and this works for me.
middleware.py
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from django.shortcuts import render
from social.exceptions import AuthCanceled
class SocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if type(exception) == AuthCanceled:
return render(request, "pysocial/authcancelled.html", {})
else:
pass
settings.py
MIDDLEWARE_CLASSES += (
'myapp.middleware.SocialAuthExceptionMiddleware',
)
The 2018 answer:
Add SocialAuthExceptionMiddleware middleware to your config:
MIDDLEWARE_CLASSES = [
...
'social_django.middleware.SocialAuthExceptionMiddleware',
]
Set SOCIAL_AUTH_LOGIN_ERROR_URL in your config:
SOCIAL_AUTH_LOGIN_ERROR_URL = '/login'
Now when you have DEBUG = False, your users will get redirected to your login page when they click cancel in social auth provider's page.
When DEBUG = True you will still see the error page in your browser during development.
Just add in
MIDDLEWARE_CLASSES = (
'social_auth.middleware.SocialAuthExceptionMiddleware',
)
and something like
LOGIN_ERROR_URL = '/'
That's all
or read http://django-social-auth.readthedocs.org/en/latest/configuration.html#exceptions-middleware
If you don't care about handling the exception do the following in your settings.py
SOCIAL_AUTH_RAISE_EXCEPTIONS = False
See this answer: How to solve Authentication process canceled error?
This is a updated imports middleware using social_django
from social_django.middleware import SocialAuthExceptionMiddleware
from social_core import exceptions as social_exceptions
from django.shortcuts import HttpResponse
from django.shortcuts import render, redirect
class FacebookAuthCanceledExceptionMiddleware(SocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if hasattr(social_exceptions, 'AuthCanceled'):
return redirect('auth_login')
else:
raise exception
Related
I have a custom middleware where I check whether incoming requests have a cookie present or not. If the cookie is not present, then it shows KeyError:.
[15/May/2021 18:00:05] "GET /api/auth/profile/ HTTP/1.1" 500 62653
Internal Server Error: /
Traceback (most recent call last):
File "F:\<dir>\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "F:\<dirs\to\middleware>\middleware.py", line 49, in __call__
myCookie = request.COOKIES['my_cookie']
KeyError: 'my_cookie'
I want it to return only a 500 Internal Server Error if the cookie is not present. How do I do this?
This is my middleware:
class AuthMiddleware:
def __init__(self, get_response=None):
self.get_response = get_response
def __call__(self, request):
if request.path == '/api/auth/profile/':
try:
myCookie = request.COOKIES['my_cookie']
// do something with the cookie
return self.get_response(request)
except jwt.ExpiredSignatureError:
// do something
return self.get_response(request)
Here, I only check whether the token has expired but I couldn't add mechanism to handle a KeyError. How do I do this?
Add another exception like this:
try:
myCookie = request.COOKIES['my_cookie']
// do something with the cookie
return self.get_response(request)
except jwt.ExpiredSignatureError:
// do something
return self.get_response(request)
except KeyError:
// do something
return self.get_response(request)
Or you can use
my_cookie = request.COOKIES.get('my_cookie', None)
if not my_cookie: # cookie not found
# do something
return self.get_response(request)
Found a workaround with HttpResponseServerError:
from django.http import HttpResponse, HttpResponseServerError
class AuthMiddleware:
...
def __call__(self, request):
...
except KeyError:
response = HttpResponseServerError()
response.write("<h2>Error: Cookie [ access ] is missing!</h2>")
return response
I think it's better to use DRF custom exceptions for this issue.
I must be going crazy...
If I have my views.py file with 48 or less lines, when I POST data to it, I see
Incomplete response received from application
However, If I have 49 lines or more I get a
NameError, 'request' is not defined
thrown on line 31 and 49, even if line 31/49 is empty.
Could someone please explain what is happening?
Also btw Django Admin - "Incomplete response received from application" does not answer my question.
veiws.py:
from django.shortcuts import render
from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.core.exceptions import *
from datetime import datetime
def remove_xss(chat, request):
return chat
def find_urls(chat, request):
new_chat = ' '.join([('{}'.format(word, word) if ('http://' in word or 'https://' in word) else word) for word in chat.split(' ')])
return new_chat
def format_chat(chat, username, request):
chat = remove_xss(chat, request)
chat = find_urls(chat, request)
request = request
return "hi"
def chat_index(request):
return render(request, 'chatroom.html')
def chat(request):
if request.method == 'POST':
chat = request.POST.get('textfield', None)
if request.user.is_authenticated():
u = request.user.username
f_chat = format_chat(chat, u, request)
else:
return HttpResponse('You must be signed in to continue')
with open('chats.txt', 'a') as chats:
chats.write(f_chat)
return render(request, 'chatroom.html')
urls.py: (Working (i think))
from chat import views
from django.urls import path
urlpatterns = [
path('/', views.chat_index),
path('chat/', views.chat)
]
Full Traceback: (when there is >=49 lines)
Traceback:
File "/home/raveivcs/virtualenv/backend/3.5/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/home/raveivcs/virtualenv/backend/3.5/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "/home/raveivcs/virtualenv/backend/3.5/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/raveivcs/backend/chat/views.py" in chat
49.
File "/home/raveivcs/backend/chat/views.py" in format_chat
31.
Exception Type: NameError at /chat/chat/
Exception Value: name 'request' is not defined
Ok, for anyone coming here, all you need to do is look in different files. The error doesn't have to be in the file you think it is in.
I'm trying to solve problem described here but code provided in that answer not works for latest django==2.2
I have tried to port this code but failed with that
settings.py:
MIDDLEWARE = ['polls.mymiddleware.CookieMiddleware',
mysite/polls/authbackend.py:
from django.contrib.auth.backends import RemoteUserBackend, UserModel
class Backend(RemoteUserBackend):
def authenticate(**credentials):
"""We could authenticate the token by checking with OpenAM
Server. We don't do that here, instead we trust the middleware to do it.
"""
try:
user = UserModel.objects.get(username=credentials['remote_user'])
print('__user exists')
except UserModel.DoesNotExist:
user = UserModel.objects.create(username=credentials['remote_user'])
print('__user not exists')
# Here is a good place to map roles to Django Group instances or other features.
return user
mysite/polls/mymiddleware.py:
from django.contrib.auth import authenticate, login, ImproperlyConfigured
class CookieMiddleware(object):
"""Authentication Middleware for OpenAM using a cookie with a token.
Backend will get user.
"""
def process_request(self, request):
if not hasattr(request, 'user'):
raise ImproperlyConfigured()
if "thecookiename" not in request.COOKIES:
return
# token = request.COOKIES["thecookiename"]
# REST request to OpenAM server for user attributes.
# token, attribute, role = identity_manager.get_attributes(token)
# user = authenticate(remote_user=attribute['uid'][0])
user = authenticate(remote_user=1) # simplified for test
request.user = user
login(request, user)
result of that:
File "C:\Users\Administrator\Desktop\my_scripts\mysite\mysite\wsgi.py", line 16, in <module>
application = get_wsgi_application()
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\core\wsgi.py", line 13, in get_wsgi_application
return WSGIHandler()
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\core\handlers\wsgi.py", line 135, in __init__
self.load_middleware()
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\core\handlers\base.py", line 37, in load_middleware
mw_instance = middleware(handler)
TypeError: object() takes no parameters
Update 1: fixed issue above, thanks to #Daniel_Rossman for that:
need to put your middleware after the SessionMiddleware in your MIDDLEWARE settings.
but got now new problem:
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\utils\deprecation.py", line 93, in __call__
response = self.process_request(request)
File "C:\Users\Administrator\Desktop\my_scripts\mysite\polls\mymiddleware.py", line 22, in process_request
login(request, user, backend='polls.mymiddleware.CookieMiddleware')
File "C:\Users\Administrator\Desktop\my_scripts\venv\lib\site-packages\django\contrib\auth\__init__.py", line 126, in login
request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
AttributeError: 'NoneType' object has no attribute '_meta'
[25/Apr/2019 12:40:07] "GET /admin/ HTTP/1.1" 500 64298
Inherit yor middleware from MiddlewareMixin like this
from django.utils.deprecation import MiddlewareMixin
class CookieMiddleware(MiddlewareMixin):
"""Authentication Middleware for OpenAM using a cookie with a token.
Backend will get user.
"""
def process_request(self, request):
if not hasattr(request, 'user'):
raise ImproperlyConfigured()
if "thecookiename" not in request.COOKIES:
return
# token = request.COOKIES["thecookiename"]
# REST request to OpenAM server for user attributes.
# token, attribute, role = identity_manager.get_attributes(token)
# user = authenticate(remote_user=attribute['uid'][0])
user = authenticate(remote_user=1) # simplified for test
request.user = user
login(request, user)
I upgraded my project from Django 1.11 to 2.2, made all the changes but came with new error that says login() got an unexpected keyword argument 'template_name'.It worked fine with the previous version of Django 1.11 (All the other urls are working, only the landing page gives the error). I couldn't find any references to this issue. Below is the error and urls and views for the issue.
Internal Server Error: /
Traceback (most recent call last):
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\User\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\User\PycharmProjects\MyWebsite\landing\views.py", line 43, in landing_validation
login_response = login(request, template_name='landing.html')
TypeError: login() got an unexpected keyword argument 'template_name'
[19/Apr/2019 16:20:00] "GET / HTTP/1.1" 500 71948
Landing\urls.py
from django.conf.urls import url
from landing.views import landing_validation
app_name='landing'
urlpatterns = [
url(r'^$', landing_validation, name='landing')
]
Landing\views.py
from django.contrib.auth import login
def landing_validation(request):
login_response = login(request, template_name='landing.html')
return login_response
C:\Users\User\venv\Lib\site-packages\django\contrib\auth__init__.py
def login(request, user, backend=None):
"""
Persist a user id and a backend in the request. This way a user doesn't
have to reauthenticate on every request. Note that data set during
the anonymous session is retained when the user logs in.
"""
session_auth_hash = ''
if user is None:
user = request.user
if hasattr(user, 'get_session_auth_hash'):
session_auth_hash = user.get_session_auth_hash()
if SESSION_KEY in request.session:
if _get_user_session_key(request) != user.pk or (
session_auth_hash and
not constant_time_compare(request.session.get(HASH_SESSION_KEY, ''), session_auth_hash)):
# To avoid reusing another user's session, create a new, empty
# session if the existing session corresponds to a different
# authenticated user.
request.session.flush()
else:
request.session.cycle_key()
try:
backend = backend or user.backend
except AttributeError:
backends = _get_backends(return_tuples=True)
if len(backends) == 1:
_, backend = backends[0]
else:
raise ValueError(
'You have multiple authentication backends configured and '
'therefore must provide the `backend` argument or set the '
'`backend` attribute on the user.'
)
else:
if not isinstance(backend, str):
raise TypeError('backend must be a dotted import path string (got %r).' % backend)
request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
request.session[BACKEND_SESSION_KEY] = backend
request.session[HASH_SESSION_KEY] = session_auth_hash
if hasattr(request, 'user'):
request.user = user
rotate_token(request)
user_logged_in.send(sender=user.__class__, request=request, user=user)
There was no need to do a landing_validation view this line solved the issue.
url(r'^$', LoginView.as_view(template_name='landing.html'), name='landing')
In Django 2.2 app I fixed similar error by using LoginView instead of login.
File users/urls.py:
from django.conf.urls import url
# from django.contrib.auth.views import login
from django.contrib.auth.views import LoginView
from . import views
app_name = 'users'
urlpatterns = [
# url(r'^login/$', login, {'template_name': 'users/login.html'}, name='login'),
url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
]
The login function that you're using is not actually a view. It's just a regular function which you can use to authenticate a user and set the session cookie, etc.
Read the docs for it's usage: https://docs.djangoproject.com/en/2.2/topics/auth/default/#django.contrib.auth.login
Judging by your code, it appears you want to use LoginView.
from django.contrib.auth.views import LoginView
def landing_validation(request):
login_response = LoginView.as_view()(request, template_name='landing.html')
return login_response
You can see that django.contrib.auth.login takes request, user, and an optional backend. There is no template_name. This hasn't changed recently, so I think you would get the same problem in 1.11, too.
It looks like you want a view function, but django.contrib.auth.login is not that. It doesn't return a response.
I'm using django-rest-auth for user signup and verify email.
I'm able to successfully send the email when a user signs up. Howvever, on email verification, I'm getting this error with the following traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
111. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in view
69. return self.dispatch(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in dispatch
87. return handler(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in get
155. return self.render_to_response(context)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in render_to_response
130. template=self.get_template_names(),
File "/Library/Python/2.7/site-packages/django/views/generic/base.py" in get_template_names
142. "TemplateResponseMixin requires either a definition of "
Exception Type: ImproperlyConfigured at /rest-auth/registration/account-confirm-email/vjohhnrf6xpkmn1jxbzaopdn0g79tdyofumeeuyuehcuja8slyz7nzq1idyifcqk/
Exception Value: TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'
Any idea on how to fix this ?
While Ricardo's answer is correct, it didn't do much to help me solve my problem. This is what I needed to do for my master urls.py:
from allauth.account.views import confirm_email
.....
url(r'^accounts-rest/registration/account-confirm-email/(?P<key>.+)/$', confirm_email, name='account_confirm_email'),
Make sure that the beginning of the url spec starts with whatever path you are using for allauth REST calls.
Of course, the above is for using the built-in view handling the confirmation.
When you use confirmation email you have two ways to do it.
Using the specified by the API or creating yours. By default it uses django-allauth and a TemplateView on reverse can be used.
If you create yours, you may have to override account_confirm_email and then post to verification_mail.
In urls.py it is defined just reverse so, depending on what you are trying to do you will have first to create your own account_confirm_email, get the required key and post it to verify-email. Here there is more information about this bug.
For the new Django versions re_path url resolver method works properly with this (?P.+) url regex.
from django.urls import re_path
re_path('rest-auth/registration/account-confirm-email/(?P<key>.+)/', CustomConfirmEmailView.as_view(), name='account_confirm_email')
Also I have customized allauth ConfirmEmailView get() method in order to redirect properly
from allauth.account.views import ConfirmEmailView
from django.contrib.auth import get_user_model
class CustomConfirmEmailView(ConfirmEmailView):
def get(self, *args, **kwargs):
try:
self.object = self.get_object()
except Http404:
self.object = None
user = get_user_model().objects.get(email=self.object.email_address.email)
redirect_url = reverse('user', args=(user.id,))
return redirect(redirect_url)
I also have the problem as I read the tutorialHere is the link ,it shows the problem as TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'
solution:
I change the location of templates filer and change the templates in the setting.py
1. In the App_Name file,I add the New folder Named:templates
2. In the settings.py: TEMPLATES = [{'DIRS': [BASE_DIR+"/templates",],}]