Django middleware when using msal for authentication - django

I Have implemented oauth2 login for users in a django app using the msal library following this guide https://medium.com/#madhok.simran8/how-to-setup-azure-oauth-2-0-sso-in-django-with-microsoft-graph-api-d2639b8f7e36.
However Im not able to set the request.user variable right, which in turn means i cant check if request.user.is_authenticated.
I believe this should be solved using the proper middleware, but Im not sure how to set it up.
This is my current middleware:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Related

What's the proper order in which Django cache middleware should be added?

I'm trying to add caching to my Django project and I'm failing to understand documentation on middleware ordering. Consider the following MIDDLEWARE list, which is mostly default:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware'
]
If I'm understanding this piece of documentation correctly, I'm supposed to add three new entries to MIDDLEWARE list. Is there more than one proper ordering for my case?
The default startproject middleware are:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
The three per-site cache middleware are given as:
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
And when we're discussing caching there's also ConditionalGetMiddleware which is related to conditional view processing:
MIDDLEWARE = [
'django.middleware.http.ConditionalGetMiddleware'
]
The question is then, what is the proper order to combine all these into one single MIDDLEWARE list? The Django documentation gives two rules specific to caching:
UpdateCacheMiddleware must come before "any other middleware that might add something to the Vary header" (and SessionMiddleware, GZipMiddleware, LocaleMiddleware do)
FetchFromCacheMiddleware needs to run after middleware that varies Vary
While it could be more subtle if you have additional custom stuff, the most natural way based on the defaults is to just bracket all the other middleware inside the cache ones. But we'll leave SecurityMiddleware up top since afaict it just checks/redirects some stuff that would be better done by something [e.g. nginx] wrapping Django itself anyway.
The CommonMiddleware was included at presumedly the right place in the startproject list already, so that one's easy.
The ConditionalGetMiddleware is tricker; a separate section of Middleware ordering hints say it goes "after GZipMiddleware […]" but overall "before any middleware that may change the response" which is a bit odd but whatever…. (Apparently the GZip middleware is discouraged/problematic anyway.)
At the end here's what I get:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.gzip.GZipMiddleware', # Caution: BREACH attack?
'django.middleware.http.ConditionalGetMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
Note that there's at least one odd interaction between ConditionalGetMiddleware and UpdateCacheMiddleware in that the former may prevent the latter from actually caching the render if/when that render gets replaced with a 304 response.
So perhaps even better would be:
MIDDLEWARE = [
'django.middleware.http.ConditionalGetMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
…avoiding Gzip and handling HTTPS/HSTS stuff in the HTTP server layer instead.

Django Superuser no longer working after implementing social login

I have recently implemented Social Login to my Django site (which is working), but have encountered an issue where if I create a superuser using the terminal that superuser login does not work.
Middleware Section of Settings.py
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django_babel.middleware.LocaleMiddleware',
'graphql_jwt.middleware.JSONWebTokenMiddleware',
'saleor.core.middleware.discounts',
'saleor.core.middleware.google_analytics',
'saleor.core.middleware.country',
'saleor.core.middleware.currency',
'saleor.core.middleware.site',
'saleor.core.middleware.taxes',
'social_django.middleware.SocialAuthExceptionMiddleware',
'impersonate.middleware.ImpersonateMiddleware']
Authentication part of Settings.py
AUTHENTICATION_BACKENDS = [
'saleor.account.backends.facebook.CustomFacebookOAuth2',
'saleor.account.backends.google.CustomGoogleOAuth2',
'graphql_jwt.backends.JSONWebTokenBackend',
'django.contrib.auth.backends.ModelBackend']
Any help is really appreciated

#csrf_protect in django services

I'm trying to use #csrf_protect in my services by following Cross Site Request Forgery protection article but it is not working for me.
This is my settings file
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'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',
'corsheaders.middleware.CorsMiddleware',
]
and this is how I'm Acquiring the token
var csrftoken = Cookies.get('csrftoken');
And this is how I'm configuring the $http provider with the cookie and header names:
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
But when I call any service, it returns 403 forbidden error. Any Idea what I'm missing or doing wrong?
Any kind of help will be appreciated.

object() takes no parameters in django 1.10

I'm trying to allow CORS in my app, so that my cross-domain javascript client can access my API, I've installed django-cors-headers. And I'm now trying to add the middleware:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # Remove this and it works
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
However this gives me a TypeError:
TypeError: object() takes no parameters
This worked fine before the django 1.10 update. Any ideas?
If you have custom middleware and you've moved from MIDDLEWARE_CLASSES to MIDDLEWARE, then you need to update your middleware. Details on: this Django documentation page. TL;DR, subclass from MiddlewareMixin instead of object:
from django.utils.deprecation import MiddlewareMixin
class FOOMiddleware(MiddlewareMixin):
pass
This issue says that django-cors-headers is no longer supported, and suggests using django-cors-middleware instead.

Django REST Framework w/ TokenAuthentication issue with CSRF/CORS

I am using TokenAuthentication in Django REST Framework to have a script remotely access my API. The domain running the API is behind a TLS certificate.
I have scoured through MANY sources, and tried many options before coming here to figure out what my problem is. In short, I continue to get the CSRF verification failed. Request aborted. error when I attempt to post.
Here is my view:
# #csrf_exempt
#api_view(['POST'])
#authentication_classes((TokenAuthentication,))
#permission_classes((permissions.IsAuthenticated,))
def create_object(request):
csrf_exempt decorator has done nothing here. So, I have also tried it on my urls.py:
url(r'^create_object/', csrf_exempt(views.create_object),),
I even tried writing a custom decorator, and using this suggestion. Even when I do this, I cannot even seem to get that decorator to execute before getting the failure. Perhaps there is an issue with the ordering of my middleware?
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
Here are my django cors settings:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = ('example.com',)
CORS_REPLACE_HTTPS_REFERER = True
As promised, here is the solution that I came up with. Admittedly, this is not perfect. I was not able to figure the underlying problem (why on HTTPS the app was not responding to csrf_exempt, or CORS_REPLACE_HTTPS_REFERER), but came up with this limited solution.
STEP 1
First, I subclassed the entire CsrfViewMiddleware class into my own version, and placed it into my middleware (changes from original quertion marked):
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', ##CHANGE
'myapp.csrf.CsrfViewMiddleware', ##CHANGE
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
At about line 160 of my version of CsrfViewMiddleware, I replaced the existing conditional to this:
acceptable_referers = ['https://%s' % u for u in settings.CORS_ORIGIN_WHITELIST] + ['http://%s' % u for u in settings.CORS_ORIGIN_WHITELIST]
if not same_origin(referer, good_referer) and referer not in acceptable_referers:
This got me past the invalid referer issue, which is fine because I am whitelisting the domains that are okay. It essentially comes to the same result as CORS_REPLACE_HTTPS_REFERER. My version cross-references the referer header with settings.CORS_ORIGIN_WHITELIST, while the CORS_REPLACE_HTTPS_REFERER method temporarily changes the request referer. Neither seems to me a sufficient enough security solution--but that is another conversation.
STEP 2
At this point, I was still getting the csrf cookie not found error. To circumvent this problem, and since csrf_exempt was not respoding (it seemed as if the middleware was executing too early), I added a new piece of middleware:
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'myapp.csrf.CsrfSkipMiddleware' ##ADDED
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', ##REMOVED
'myapp.csrf.CsrfViewMiddleware', ##ADDED
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
This new piece of middleware essentially sets a flag on the request object (_dont_enforce_csrf_checks) that already exists on the stock version of CsrfViewMiddleware and tells the script to ignore the rest of the csrf check. In order to do that, it checks the page path against a list of paths that I have selected to remove from csrf in settings.CSRF_SKIP_URLS.
class CsrfSkipMiddleware(object):
def process_request(self, request):
CSRF_SKIP_URLS = [re.compile(expr) for expr in settings.CSRF_SKIP_URLS]
path = request.path_info.lstrip('/')
if any(m.match(path) for m in CSRF_SKIP_URLS):
setattr(request, '_dont_enforce_csrf_checks', True)
THOUGHTS
Again, not the best implementation. But, for my purposes it works. Thoughts are still welcome.
I see you're using django cors headers.
I was facing a similar issue and specifying:
CORS_REPLACE_HTTPS_REFERER = True in settings.py resolved the problem.