Axios not storing Django session cookie - django

I have a Django REST Framework API backend for my Vue app. I'm trying to use Django sessions for anonymous users but either Django isn't sending or Axios can't read the session cookie.
A new session is being created by checking Session.objects.all().count()
I'm trying to store cart data using JWTAuthentication for authenticated users and SessionAuthentication for anonymous users.
# settings.py
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'localhost:8080',
'127.0.0.1:8080',
)
SESSION_COOKIE_HTTPONLY = False
I've tried toggling SESSION_COOKIE_HTTPONLY in settings.py but still not able to see the cookie.
When intercepting the response the CSRF cookie is sent but the session cookie isn't included.
import axios from 'axios'
import Cookie from 'js-cookie'
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.defaults.withCredentials = true
axios.interceptors.response.use(response => {
const sessionCookie = Cookie.get()
console.log('Cookie', sessionCookie)
return response
})
In my DRF API tests I can see that the session cookie is in the response.
Set-Cookie: sessionid=zgndujlppk4rnn6gymgg1czhv1u0rqfc; expires=Thu, 11 Apr 2019 11:27:32 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
class Test(APITestCase):
def test_get(self):
response = self.client.get('/store/1/')
print(response.cookies['sessionid']

The issue was I was visiting the site at the URL localhost:8080 but the cookie was being saved under 127.0.0.1.
Changing the URL to 127.0.0.1:8080 solved the problem.

Related

Programmatically set source database in Apache Superset

I am running Apache Superset on AWS-ECS to facilitate a connection directly with our RDS. This connection works, but has to be configured manually.
Is there a way to programmatically configure source databases with Apache Superset?
I have tried setting SQLALCHEMY_DATABASE_URI, but that is only for the Superset back-end configuration and settings.
Superset has an API, so you can create/update/delete databases via HTTP requests. Authorization is non-trivial, since you need login first to get a CSRF token and store cookies:
import requests
from bs4 import BeautifulSoup
from yarl import URL
superset_url = URL('https://superset.example.org/')
session = requests.Session()
# get CSRF token
response = session.get(superset_url / "login/")
soup = BeautifulSoup(response.text, "html.parser")
csrf_token = soup.find("input", {"id": "csrf_token"})["value"]
# get cookies
session.post(
superset_url / "login/",
data=dict(username=username, password=password, csrf_token=csrf_token),
)
# create database
database = {
"database_name": "my db",
"sqlalchemy_uri": "gsheets://",
...
}
session.post(
superset_url / "api/v1/database/",
json=database,
headers={"X-CSRFToken": csrf_token},
)

Django CSRF and axios post 403 Forbidden

I use Django with graphene for back-end and Nuxt for front-end. The problem appears when I try post requests from nuxt to django. In postman everything works great, in nuxt I receive a 403 error.
Django
# url.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', GraphQLView.as_view(graphiql=settings.DEBUG,
schema=schema)),
]
# settings.py
CORS_ORIGIN_WHITELIST = 'http://localhost:3000'
CORS_ALLOW_CREDENTIALS = True
CSRF_USE_SESIONS = False
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_SAMESITE = None
NuxtJs
# nuxt.config.js
axios: {
baseURL: 'http://127.0.0.1:8000/',
debug: false,
progress: true,
credentials: true
},
# plugins/axios.js
await $axios.onRequest((config) => {
config.headers.common['Content-Type'] = 'application/json'
config.xsrfCookieName = 'csrftoken'
config.xsrfHeaderName = 'X-CSRFToken'
const csrfCookie = app.$cookies.get('csrftoken')
config.headers.common['X-CSRFToken'] = csrfCookie
console.log(config)
# store/contact.js
import { AddMessage } from '../queries/contact.js'
export const actions = {
async send() {
const message = await this.$axios({
url: 'api/',
method: 'POST',
data: AddMessage
})
}
}
# queries/contact.js
export const AddMessage = {
query: `
mutation AddContact($input: AddMessageInput!){
addMessage(input: $input){
message{
name
email
body
terms
}
}
}
`,
variables: `
{
"input":{
"name": "test",
"email": "test#test.com",
"body": "test",
"terms": true,
}
}
`,
operationName: 'AddMessage'
}
Somethig that
Here are request headers from axios post. Something strange for me is the cookie with a wrong value. The good value of token is present in X-CSRFToken header.
Here is the log from axios post request. Another strange thing for me is the undefined headers: Content-Type and X-CSRFToken
Thank you!
I resolved this problem and I want to share the solution here.
The problem with wrong cookie value was generated by the front end app that managed (I don't remember how) to get csrf cookie from the back end app. In X-CSRFToken header was token received from response's Set-cookie header and in Cookie header was the cookie from back end app.
After I changed localhost with 127.0.0.1 and added
config.xsrfCookieName = 'csrftoken' in axios plugin
I was able to separate the apps, save and use cookies independent.
The second problem, with undefined headers was generated by axios. These 2 line of code resolved the problem. These were added also in axios onRequest method.
config.xsrfHeaderName = 'X-CSRFToken'
config.headers['Content-Type'] = 'application/json'

Django Azure AD Integration

I'm currently integrating SSO using Azure AD for a Django Project. I'm currently using the package: https://github.com/leibowitz/django-azure-ad-auth . I have followed the docs to setup the Azure AD Authentication . On entering the application url, it takes me to the microsoft login page and after entering the credentials it's redirected to the application. But on redirection to the application after the Azure Auth, the code checks in the session for 'nonce' & 'state' variables , which are strangely returned as None and hence the application redirects to the failure url.
#never_cache
def auth(request):
backend = AzureActiveDirectoryBackend()
redirect_uri = request.build_absolute_uri(reverse(complete))
nonce = str(uuid.uuid4())
request.session['nonce'] = nonce
state = str(uuid.uuid4())
request.session['state'] = state
login_url = backend.login_url(
redirect_uri=redirect_uri,
nonce=nonce,
state=state
)
return HttpResponseRedirect(login_url)
#never_cache
#csrf_exempt
def complete(request):
backend = AzureActiveDirectoryBackend()
method = 'GET' if backend.RESPONSE_MODE == 'fragment' else 'POST'
original_state = request.session.get('state')
state = getattr(request, method).get('state')
if original_state == state:
token = getattr(request, method).get('id_token')
nonce = request.session.get('nonce')
user = backend.authenticate(token=token, nonce=nonce)
if user is not None:
login(request, user)
return HttpResponseRedirect(get_login_success_url(request))
return HttpResponseRedirect('failure')
This is the code used for authentication.
Settings.py sample is given below:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'azure_ad_auth.backends.AzureActiveDirectoryBackend',
)
LOGIN_REDIRECT_URL = '/login_successful/'
AAD_TENANT_ID = 'd472b4f4-95c5-4eb3-8a9a-3615c837eada'
AAD_CLIENT_ID = '75e38b53-8174-4dc6-a8f6-bb7a913f1565'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_SAVE_EVERY_REQUEST = True
SESSION_COOKIE_AGE = 86400 # sec
SESSION_COOKIE_DOMAIN = None
SESSION_COOKIE_NAME = 'DSESSIONID'
SESSION_COOKIE_SECURE = True
Traceback
TypeError at /TypeError at /project/azure/complete/
must be str, not NoneType
Request Method: POST
Request URL: http://testdomain.com/project/azure/complete/
Django Version: 2.2.4
Exception Type: TypeError
Exception Value:
must be str, not NoneType
Exception Location: /home/project/azure_auth/views.py in complete, line 57
Python Executable: /home/project/app/venv/bin/python3
Python Version: 3.6.8
Python Path:
['/home/project/app/project',
'/home/project/app/venv/bin',
'/home/project/app/venv/lib64/python36.zip',
'/home/project/app/venv/lib64/python3.6',
'/home/project/app/venv/lib64/python3.6/lib-dynload',
'/usr/lib64/python3.6',
'/usr/lib/python3.6',
'/home/project/app/venv/lib/python3.6/site-packages']
Server time: Tue, 19 Nov 2019 05:21:10 +0000/azure/complete/
must be str, not NoneType
Request Method: POST
Request URL: http://testdomain.com/project/azure/complete/
Django Version: 2.2.4
Exception Type: TypeError
Exception Value:
must be str, not NoneType
Exception Location: /home/project/app/project/azure_auth/views.py in complete, line 57
Python Executable: /home/project/app/venv/bin/python3
Python Version: 3.6.8
Python Path:
['/home/project/app/project',
'/home/project/app/venv/bin',
'/home/project/app/venv/lib64/python36.zip',
'/home/project/app/venv/lib64/python3.6',
'/home/project/app/venv/lib64/python3.6/lib-dynload',
'/usr/lib64/python3.6',
'/usr/lib/python3.6',
'/home/project/app/venv/lib/python3.6/site-packages']
Server time: Tue, 19 Nov 2019 05:21:10 +0000
/home/project/app/project/azure_auth/views.py in complete
f.write("nonce -->"+nonce+"\n") …
▼ Local vars
Variable Value
backend
<azure_auth.backends.AzureActiveDirectoryBackend object at 0x7f5c688dce80>
data
['82aff4f9-2cc0-4521-aea7-ad3281d20774\n',
'ba821364-86c9-4233-881f-bdc772f7c488\n']
f
<_io.TextIOWrapper name='t1.txt' mode='w' encoding='UTF-8'>
method
'POST'
n
'82aff4f9-2cc0-4521-aea7-ad3281d20774'
nonce
None
original_state
None
request
<WSGIRequest: POST '/project/azure/complete/'>
state
'fd93da6a-9009-4363-9640-9364df7f64df'
token
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyIsImtpZCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyJ9.eyJhdWQiOiI0MDMyODJjZi1kYjlmLTQ1OTYtOWM1My0wMmI1MTA2ZDA0MDIiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mYmM0OTNhOC0wZDI0LTQ0NTQtYTgxNS1mNGNhNThlOGMwOWQvIiwiaWF0IjoxNTc0MTQwNTY5LCJuYmYiOjE1NzQxNDA1NjksImV4cCI6MTU3NDE0NDQ2OSwiYWlvIjoiNDJWZ1lCQSt4TFhqNEdVTjRRWEJiU3ZOZmF4NXBHY2NPenFoNzFuNDlXMmxnYTYzMjIwQiIsImFtciI6WyJwd2QiXSwiZmFtaWx5X25hbWUiOiJFIEsgUyIsImdpdmVuX25hbWUiOiJTdXNyZWV0aGEiLCJpbl9jb3JwIjoidHJ1ZSIsImlwYWRkciI6IjE4Mi43NS4xNjcuMTg4IiwibmFtZSI6IkUgSyBTLFN1c3JlZXRoYSIsIm5vbmNlIjoiODgyNTg4ZjgtMGM3MC00Y2JlLTk4MTktY2JkNjUyZmI0MDQ5Iiwib2lkIjoiNTU0ZjYzZWEtOTg4Yi00MmMwLTk4NjUtMTIxMDNkZTdhZTBmIiwib25wcmVtX3NpZCI6IlMtMS01LTIxLTYwMzE5MzI1LTExNjA5ODI5NTEtMTYwMTc3MzkwNy02NTg1OTMiLCJzdWIiOiI2aERUa1hYYkN3Wm5rcHEwSU9wRTRVWk56RHZlRFhvVjM3RGV5U3dkaDZRIiwidGlkIjoiZmJjNDkzYTgtMGQyNC00NDU0LWE4MTUtZjRjYTU4ZThjMDlkIiwidW5pcXVlX25hbWUiOiJTRTA3NTA0OEBjZXJuZXIubmV0IiwidXBuIjoiU0UwNzUwNDhAY2VybmVyLm5ldCIsInV0aSI6IkZTQmhnVDg4UTAyUHNfU293ZDdtQUEiLCJ2ZXIiOiIxLjAifQ.Rvc6xcPRZ01iebYtEyAWeyDnQEUVtqV1L1mapr658jLog-_yIASyEm3kMrkt6dIWWEO3dJSe3k05xOJlbnHqcjaR5LKAwOZzGR_oBmyIyB8-IvuEankNVpwYtcz8mY7kFr6AqQmIsx7xLLgv4grp-bSy4eRqjk36VeLX_LwMBuM_U6V70w0gXN1vvFCj0tjsv-VtTAmNgvdxS0ltzdD3rzZ87DoXbPWmoozLtO9WBRsJvMuvn-frBtYUYkIhs3I-eVAO9ZG2IWEuLQx6k7RBmzX6HgFi9SVpyEhNru7fmwO-qj5uRj9FQa45lCZluUV25o_AV1NQ94d5lnFyeMh7uw'
user
None
I got the above error while trying to write the session variables to file (for debugging.)
I know this question is a bit old, but the session won't be able to be retrieved (and with it the original state and nonce), and will fail the comparison if the cookie is not being sent by the browser.
The cookie is not sent by default in django 2.1+, since the default settings add SameSite=Lax
The cookies used for django.contrib.sessions, django.contrib.messages,
and Django’s CSRF protection now set the SameSite flag to Lax by
default. Browsers that respect this flag won’t send these cookies on
cross-origin requests. If you rely on the old behavior, set the
SESSION_COOKIE_SAMESITE and/or CSRF_COOKIE_SAMESITE setting to None.
https://docs.djangoproject.com/en/3.0/releases/2.1/#samesite-cookies
In theory this should still send the cookie (from what I understand), but for some reason chrome doesn't seem to. There's something I clearly do not understand, so if anyone knows better please comment.
Anyway, changing the setting via SESSION_COOKIE_SAMESITE = None should work.

Django React Axios

I am trying to make a post request to a Django server using React with Axios. However, I am getting a redirect 302 on the server side.
Just followed all suggestions in this post here CSRF with Django, React+Redux using Axios
unsuccessfully :(
However, what I have done so far is the following:
Sat the default axios CookieName and HeaderName (on the javascript side):
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.xsrfCookieName = "XCSRF-Token";
Got this in settings.py as well:
CSRF_COOKIE_NAME = "XCSRF-Token"
And here is how the post request looks like:
axios(
{
method: 'post',
url: `/api/${selectedEntryType}_entry`,
data: {
"test": "test"
},
headers: {
'X-CSRFToken': document.cookie.split('=')[1],
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
}
}
)
Another thing that I have tried is to make the post request from the Django rest api UI:
and it does work successfully.
The only differences in the Request Headers when I make the request from the UI and from JS are:
Accept, Content-Length, and Referer, which I don't see how could they be problematic.
Please help.
Managed to fix it by changing the url (url:'/en/api/endpoint/') I was posting to, because apparently for a POST request:
You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/en/api/endpoint/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings
After that I started getting Forbidden 403, but by adding:
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
#method_decorator(csrf_protect)
def post(self, request):
return Response()
and also changed the defaults in JS to:
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.xsrfCookieName = "csrftoken";
and removed CSRF_COOKIE_NAME = "XCSRF-Token" from settings.py.
It worked.
Hope this helps somebody in the future.

Can't access csrf cookie sent by server via Set-Cookie (Django + Angular2)

I'm experimenting with an app running on Angular 2 in the frontend and Django as API and I can't access the CSRF cookie sent from Django.
As you can see, I am getting back the cookie from the server but I cannot access it from the browser (document.cookie) or Angular 2 (using the ng2-cookies module).
Everything was working while testing on localhost, now client and server are running on different hosts and this might be the reason of the problem.
Client running on https://django-angular2-movies.firebaseapp.com/
Server running on https://glacial-shore-18891.herokuapp.com
This is part of the settings I'm using on Django:
settings.py
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_SECURE = False
CSRF_TRUSTED_ORIGINS = ['django-angular2-movies.firebaseapp.com']
ALLOWED_HOSTS = ['*']
Other things that I have tried, but didn't help:
Removing the CSRF_TRUSTED_ORIGINS setting
Adding CSRF_COOKIE_DOMAIN = 'django-angular2-movies.firebaseapp.com'
Using { withCredentials: true } in the request sent from the client
Using the #ensure_csrf_cookie decorator on Django views
What am I doing wrong?
Thanks