middleware does an infinite redirect - django

I've already read this but the answer doesnt fit my needs.
I've made this very simple middleware:
class RedirectIfUserIsNotActiveMiddleware(object):
"""
Middleware to redirect if account is disabled
"""
#staticmethod
def process_request(request):
if not request.user.is_active:
try:
# test to see if not already on the right url:
a = resolve(request.path)
if a.url_name != settings.URL_REDIRECT_USER_NOT_ACTIVE:
return HttpResponseRedirect(
reverse_lazy(settings.URL_REDIRECT_USER_NOT_ACTIVE))
# request.path do a 404 if URL unknown -> do nothing :
except Resolver404:
pass
And I've added this here:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'third_party.hqf_middleware.RedirectIfUserIsNotActiveMiddleware',
)
But when the account is disabled I get an infinite loop with the message on the webbrowser: "mywebsite.com redirected you too many times.".
In my settings I have this:
URL_REDIRECT_USER_NOT_ACTIVE = 'my_home_profile_account_desactivated'
And the URL I'm trying to get is always (even each time step by step) /en/my-home/profile/edit
What am I missing?

It looks as if the my_home_profile_account_desactivated view is redirecting to your login page, and then the middleware redirects back to my_home_profile_account_desactivated, creating a redirect loop.
You should be able to break the authentication loop by changing the middleware so that you only redirect users that are authenticated and inactive.
#staticmethod
def process_request(request):
if request.user.is_authenticated() and not request.user.is_active:
...

Related

Django csrf token not refreshed after first login

I have hosted a website at http://cognezic-dev.ap-south-1.elasticbeanstalk.com/login/. On closer inspection, the form has the same csrf token across page refreshes and browsers, which I suspect to be the cause of the issue,this works fine on the local django server.Dont know where this is being cached. I have added CSRF Middleware in the settings.py too.
You can use the test credentials as username bismeet and password bis12345 for testing.
I have also tried creating a custom middleware as follows:
from django.middleware.csrf import rotate_token, CsrfViewMiddleware
from django.utils.deprecation import MiddlewareMixin
class CSRFRefresh(CsrfViewMiddleware,MiddlewareMixin):
def process_response(self, request, response):
print("Custom MiddleWare called")
rotate_token(request)
return response
But it still fails.
My settings.py with custom middleware contains:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'solvesto.middleware.csrf_refresh.CSRFRefresh'
]
If not using the custom middleware,I use:
'django.middleware.csrf.CsrfViewMiddleware'
instead of
'solvesto.middleware.csrf_refresh.CSRFRefresh'
The only last resort I see to make this work is to remove csrf altogether,which is of course,bad for security.
I removed the csrf security,no other solution,works now.

Delete header in django rest framework response

I'm trying to delete Server header from django rest framework response, but I didn't find an easy way, so I create a middleware to delete it.
This is my first try:
middleware.py
class RemoveHeaders(object):
def process_response(self, request, response):
response['Server'] = ''
return response
This middleware works ok, but the problem is that it fills server header with empty string and not delete it. so I tried the next:
class RemoveHeaders(object):
def process_response(self, request, response):
del response['Server']
return response
But It doesn't work. server header continues.
How can I delete server header?, or do you know another alternative?
thanks
Updated, these are my middlewares, maybe someone is override server header, case it doesn't exist?
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'my_api.middleware.RemoveHeaders'
)
I just had the exact same problem. Your approach with
del response['Server']
Is correct!
However, you need to move your middleware to be the first. As other middlewares will add headers after the response is constructed, so the order of application is bottom-up. Your middleware has to be the first one to have the "last word".

Exclude middleware from caching

I have very simple middleware that track numbers of "hits" of an object.
class HitCount():
def process_view(self, request, view_func, view_args, view_kwargs):
if request.resolver_match.url_name == 'article_view':
try:
Article.objects.filter(slug=view_kwargs['slug']).update(hit_count=F('hit_count')+1)
except:
pass
The problem is, it doesn't work properly when "per-site" cache is enabled.
"hit_count" field (PositiveIntegerField) is updated only once per 5 minutes (cache timeout 300s), no matter how many times page was visited during that "5 minutes".
It doesnt have to be accurate, beacuse "hit_count" field isn't even displayed on front side. I need it only, to order articles via popularity. But "5 minutes measurement error" is too much.
How can I exclude that middleware from caching? Do I need to disable cache for whole view?
settings file, I tried to change middleware order, but no effect.
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'blog.middleware.HitCount',
'django.middleware.cache.FetchFromCacheMiddleware',
)
view
class ArticleDetailView(DetailView):
queryset = Article.objects.published()
template_name = 'article.html'
The FetchFromCache middleware is fetching the page from the cache during process_request.
That means that the process_view middleware is never called.
You could try changing your middleware to override process_request instead. However, that might be tricky, because you won't have access to request.resolver_match.

Django 'WSGIRequest' object has no attribute 'set_cookie'

I keep on getting this exception when I do request.set_cookie() in the process_view of a custom middleware class. Here is the order of middleware classes in my settings.py:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'website.middleware.UserLastActiveMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
)
To start off with, set_cookie() is a method of HttpResponse, not HttpRequest, as you set cookies in your response to a requests.
Secondly, your middleware should come after AuthenticationMiddleware, since presumably it has to do with users.
You should set_cookie() call from response object.
Example:
def process_response(self, request, response):
...
response.set_cookie('user_agreement', user_agreement, domain='.mysite.com')
return response
You can take a look at this question: Django: WSGIRequest' object has no attribute 'user' on some pages?
This problem usually occurs when you do not add the trailing slash because then a redirect is done to the url containing a trailing slash

etag and last modified headers for django app not being set

I am trying to set the etag header using the condition decorator with Django 1.3.
I am using the following:
#condition(etag_func=profile_etag, last_modified_func=profile_last_modified)
#require_person_viewed_is_verified
def profile(request, id):
"""
Return profile for person id.
If profile is not verified only staff and self can view.
"""
user = request.user
...
with a middleware classes of
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'johnny.middleware.LocalStoreClearMiddleware',
'johnny.middleware.QueryCacheMiddleware',
# 'django.middleware.cache.CacheMiddleware',
'django.middleware.http.ConditionalGetMiddleware',
'pybb.middleware.PybbMiddleware',
)
USE_ETAGS = True
I am not getting the etag or last modified headers being set in the http response. Any ideas please?
I was using CharlesProxy (which is a great tool btw) and I had no caching enabled! School boy error I know!