Disable anonymous user cookie with Django - django

I use django auth for my website, which needs to have the session middleware installed.
Django session middleware always adds a session cookie, even for anonymous users (users that are not authenticated). When they authenticate the cookie is replaced by another one indicating the user is logged-in.
I want to disable the anonymous user cookie for caching purposes (varnish).
Is there a way to disable anonymous user cookies without removing session middleware which is necessary for apps using auth?

Session data is set in the cookie in the process_response of SessionMiddleware. This function doesn't use any setting or request.user, so you do not have any way of knowing inside this method whether the user is a logged in user or an anonymous user. So, you can't disable sending the session cookie to the browser.
However if you want this functionality then you can subclass SessionMiddleware and overide process_response.
from django.contrib.sessions.middleware import SessionMiddleware
from django.conf import settings
class NewSessionMiddleware(SessionMiddleware):
def process_response(self, request, response):
response = super(NewSessionMiddleware, self).process_response(request, response)
#You have access to request.user in this method
if not request.user.is_authenticated():
del response.cookies[settings.SESSION_COOKIE_NAME]
return response
And you can use your NewSessionMiddleware in place of SessionMiddleware.
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'myapp.middleware.NewSessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
)

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.

Looking for some help on Django authentication with Angular login page

I have an angular login page that sends an Ajax request to my django server (listening on a separate port from the angular application), and I am able to log my user in but a session cookie is not getting returned in the response for the client to store in the angular app. Here is what my backend settings.py looks like the for authentication specific stuff:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',]
# Here are the session specific settings
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_AGE = 1800 # The age of session cookies, in seconds
CORS_ORIGIN_ALLOW_ALL = True
And here is my login view function that is hooked up to my login path:
#csrf_exempt
#require_POST
def login_view(request: HttpRequest):
payload = request.body.decode()
body = json.loads(payload)
username = body['username']
password = body['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)# Log the user in
return HttpResponse('Success')
else:
return HttpResponseBadRequest()
I am trying to used cookie/ session based authentication so that if the user closes the page and relaunches it before the session time has expired, it will direct them back to the landing page, and for a specific input select field only certain options are supposed to be returned based on the user, and that would need to be handled via the session authentication. Is there something that is not correct in my settings file?
Try to set SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE to False, maybe because your request is insecure
Django CSRF Cookie Not Set

django rest framework csrf token missing or incorrect

hello i'm using django rest-auth and i have this problem in /password/change/ it allways return csrf token missing or incorrect problem :
I am making the request fr an android app I'm developing
my settings are :
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_auth.registration',
'allauth',
'allauth.account',
'allauth.socialaccount',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
versions :
django-rest-auth==0.9.1
djangorestframework==3.6.2
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
remove 'rest_framework.authentication.SessionAuthentication' from DEFAULT_AUTHENTICATION_CLASSES,if you still need browsable api view for DRF, use ModHeader in chrome。
after reading the doc of django rest framework official i and a lot of help come from #Todor comment i realize that i should only put TokenAuthentification in the rest authentication classes because sessionAuthentication expect a csrf value in the request but android can't give that so i use a token as in the doc in every request and that's it !
Are you properly storing and forwarding cookies from the Android networking library? I have very little familiarity with Ionic/Android, but the way that Django's CSRF checks work is this:
Check if a CSRF token is provided in the body as csrfmiddlewaretoken
If no such parameter exists, check for a cookie called csrftoken
if no such cookie exists, fall back to the HTTP_X_CSRFTOKEN header
The cookie name and header name can be customized in settings.
So what I'm getting at is, what method are you using above to send the CSRF token? On mobile, it's normally sorta tough to get a CSRF token for the request because the client generates the form (where on web, Django generates the form and injects the CSRF token).
That said, it is also common to make endpoints CSRF exempt, and it seems like you're using a third party library for these endpoints, so I'm not sure why it's requiring a CSRF token. You can check the project's documentation.
The other possibility is that you've bound your own view at that URL, and you're reaching that view instead of the one from the library you're using. It's sort of hard to tell. Why don't you first try the request using DRF's Browsable API?
I get this error when I was trying to host my website on Apache server.
If I run without Apache server (python manage.py runserver) everything is fine.
To solve this error:
Open Apache configuration file - httpd.conf
Add following line:
WSGIPassAuthorization On
Here's my quick solution that isn't good for production unless you fork the rest-framework repo with your changes... And well it disables the functionality for SessionAuthentication.
If you are going to be using your api with a browser-less front-end like a mobile app, which does not allow cross site requests to be made (as there is no browser from which a request can be made i.e. the app will not be able to open up links sent to you by others/you cannot navigate the web traditionally inside of it) Then it's as simple as this:
To remove the functionality, go to the rest_framework site package. Inside of it is a authentication.py file, and inside of it, there's is a class called 'SessionAuthentication'. In here there's a enforce_csrf() function which enforces the csrf by raising an exception when a csrf token isn't present in a request. Simply comment out its body and it will no longer care about csrf.
Here's what the authentication.py SessionAuthentication class looks like, do the following:
class SessionAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
Returns a `User` if the request session currently has a logged in user.
Otherwise returns `None`.
"""
# Get the session-based user from the underlying HttpRequest object
user = getattr(request._request, 'user', None)
# Unauthenticated, CSRF validation not required
if not user or not user.is_active:
return None
self.enforce_csrf(request)
# CSRF passed with authenticated user
return (user, None)
def enforce_csrf(self, request):
"""
Enforce CSRF validation for session based authentication.
"""
##### Comment Out Below: ###########
# check = CSRFCheck()
# # populates request.META['CSRF_COOKIE'], which is used in process_view()
# check.process_request(request)
# reason = check.process_view(request, None, (), {})
# if reason:
# # CSRF failed, bail with explicit error message
# raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
So, in case you're wondering if this is a bad idea or not, because all requests are intentionally made inside a mobile app/controlled exclusively by the mobile app in most cases, it does not operate within the same environment as a browser. It's hard for a user to accidentally follow a link or for a script . Note, this does not completely remediate the vulnerability, but the odds of it happening are incredibly unlikely and would most likely not occur directly through the mobile app
I wanted use SessionAuthentication to have the current user in rest views, i resolved it sending authorization header with the token value in each request, i am using JSON web token authentication too
Well the solution is simple: you need to add the CSRF token when you make your request. How you would do that, specifically, we can't answer, because we have no idea how you're making the request. i.e. show some code.

how to define a custom wsgi middleware for django

I want to write a custom wsgi middleware, which is called on every incoming request. It checks the url, and if the user is authenticated and allows the request to proceed or rejects it.
What is the best way to add wsgi middleware in django ?
Why do you want to do this as a WSGI middleware, specifically? Django doesn't operate particularly well with those - there was some work a few years ago to try and harmonize Django middleware with WSGI middleware, but it didn't really get anywhere.
Django has its own version of middleware, which is very well documented, and your request could be done in about three lines.
You do not need a wsgi middleware here and can easily use django middleware.
some_app/middleware.py
from django.http import HttpResponseForbidden
class AuthenticateMiddleware(object):
def process_request(self, request):
#do something with request.path
if request.user.is_authenticated():
#can do something or just pass
#but do not return a response from here
else:
#return a response from here so that view doesn't get called
return HttpResponseForbidden()
process_request() of any middleware is called before the view is processed. If you return an instance of HttpResponse from this method then the view will not be called. Since HttpResponseForbidden is a subclass of HttpResponse, so the view will not be called if the user is not authenticated.
You need to add this custom middleware to MIDDLEWARE_CLASSES.
settings.py
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'some_app.middleware.AuthenticationMiddleware',
)

Django - Losing Auth Session

I am with some trouble in Django...
After login I am losing auth session for some pages.
If I access "accounts/login/","accounts/logout/",""accounts/register/" the session always will be there, but if I access different page I cant access the user variable.
This is strange because I am using the same "base.html" for all pages and inside has the logic "if user.is_authenticated", how I said this condition is true just when I access pages that have "accounts" in the URL.
in the settings file I enabled theses three middleware:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
Thanks
Just a guess here: are you including RequestContext in your context in the views that you cannot access user?
In other words, if you call generic views the RequestContext is automatically included but if you are using render_to_response() then you need to call it like this:
return render_to_response('template_name',
{ your context dict },
context_instance=RequestContext(request))