Django Rest Framework's IsAuthenticated() method is failing for AnonymousUser - django

I have a ListView and it has permission set to IsAuthenticated, when I hit the URL in an incognito window, I'm able to view the data without having the user logged in.
Here is my serializer
class BlogListSerializer(ModelSerializer):
url = HyperlinkedIdentityField(
view_name="blog_api:post_detail",
lookup_field="slug"
)
class Meta:
model = Blog
fields = [
'url',
'title',
'category',
'date',
'publish',
'draft'
]
Below is my view
from rest_framework.permissions import IsAuthenticated
class BlogListAPIView(ListAPIView):
queryset = Blog.objects.filter(publish=True, draft=False)
serializer_class = BlogListSerializer
permission_classes = [IsAuthenticated]
Settings files
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
Middleware settings
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',
]
So what's happening is, when I try to access the user by calling get_object on BlogListAPIView, it throws an error is not JSON serializable. For some reason, middleware is taking AnonymousUser as a User. If there is AnonymousUser logged in it should fail IsAuthenticated permission. This is what basically should happen
Why AnonymousUser is getting accessed and IsAuthenticated() failing?

There is certainly some other problems that is not listed in your question. I created a fresh project with snippets you provided and will get http 401 when I hit the URL without logging in. I provided codes in Github:
get https://github.com/Rmaan/pastebin/tree/so-47596482
runserver and browse to http://localhost:8000/blog

The issue was gone by upgrading from Django 1.9 to Django 1.10 and using DRF 3.3.7.

Related

Use TokenAuthentication AND SocialAuthentication from AllAuth

I've created a new Django Rest API thanks to Django Rest Framework and I want to use two type of authentication : TokenAuthentication AND SocialAuthentication with two providers Facebook and Google.
Token authentication is success (with this syntax : Authorization: Token <token>. However, I can't get it to work with the SocialAuthentication. When I get the access_token from my POST in GoogleSocialLoginView, I can't use it to login in my others API call headers (I use an authenticated permissions for others CRUD calls). My syntax for social authentication is :
Authorization : Bearer <token>
So the users are registered successfully in database, but they can't authenticated us to the API after.
This is a part of my settings.py
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework_swagger',
'rest_framework.authtoken',
"dj_rest_auth",
'dj_rest_auth.registration',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.google',
# Local apps we created
'api',
]
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',
]
ROOT_URLCONF = 'thetiptop.urls'
AUTH_USER_MODEL = 'api.Users'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS':'rest_framework.schemas.coreapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
REST_AUTH_SERIALIZERS = {
"LOGIN_SERIALIZER": "api.serializers.CustomLoginSerializer",
}
REST_USE_JWT = True
ACCOUNT_LOGOUT_ON_GET = True
OLD_PASSWORD_FIELD_ENABLED = True
SITE_ID = 2
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
CORS_ALLOW_ALL_ORIGINS = True
SOCIALACCOUNT_QUERY_EMAIL = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': ['email'],
'AUTH_PARAMS': { 'access_type': 'online' }
},
'facebook': {
'METHOD': 'oauth2',
'SCOPE': ['email'],
'AUTH_PARAMS': {'auth_type': 'reauthenticate'},
'INIT_PARAMS': {'cookie': True},
'LOCALE_FUNC': lambda request: 'en_US',
'EXCHANGE_TOKEN': True,
'VERIFIED_EMAIL': False,
'VERSION': 'v13.0'
}
}
My url.py file list this URL :
path('auth/login/', obtain_auth_token, name='login'),
path('auth/', include('dj_rest_auth.urls')),
path('auth/registration/', include('dj_rest_auth.registration.urls')),
path('auth/facebook/', FacebookLogin.as_view(), name='fb_login'),
path('auth/google/', GoogleLogin.as_view(), name='google_login'),
path('accounts/', include('allauth.urls')),
And finally, the GoogleLogin and FacebookLogin are the same as :
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
class FacebookLogin(SocialLoginView):
adapter_class = FacebookOAuth2Adapter
class GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
client_class = OAuth2Client
Finally, I use this type of authentication for others CRUD calls :
from rest_framework import permissions
permission_classes = [permissions.IsAuthenticated]
Do you know a solution to use a token authentication and a allauth social authentication in the same User class ?
PS: I'm consuming the API from an Angular app.
It's important to keep in mind that there is a difference between the default authentication system in Django and the authentication system for DRF. In your DRF configuration, you have only specified two classes: rest_framework.authentication.SessionAuthentication and rest_framework.authentication.TokenAuthentication. The SessionAuthentication is the only one that is compatible with the default Django session authentication backend (but that may not be what you want anyhow).
As covered in the DRF API guide if you are using session-based authentication, you must include a CSRF token for authenticated requests:
If you're using an AJAX-style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as PUT, PATCH, POST or DELETE requests. [...]
CSRF validation in REST framework works slightly differently from standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens.
So, if you are using a user's session (assuming you've authenticated the user's session previously) you will need to pass CSRF tokens when calling the DRF API in addition to the session cookie.
You may want to consider using an authentication method that works directly with DRF such as one recommended in the DRF docs like drf-social-oauth2. Then add it to your DRF authentication classes directly.

Django CSRF missing or Sessions middleware required

When trying to create a django(2) rest framework api, I keep getting this error.
Forbidden (CSRF token missing or incorrect.): /login/
After doing some research the problem might be with sessions authentication which I don't really need since I will be replying on token based auth. When I try to remove some of the session auth from my settings I end up getting this.
AssertionError: The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.sessions.middleware.SessionMiddleware' before 'django.contrib.auth.middleware.AuthenticationMiddleware'.
Settings.py snippet
INSTALLED_APPS = [
# API (v1)
'apiV1.v1.accounts.apps.AccountsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Requirements
'corsheaders',
'rest_framework',
'rest_framework.authtoken',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'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',
]
ROOT_URLCONF = 'apiV1.urls'
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.TokenAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
),
}
Views.py
from django.contrib.auth import authenticate
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from apiV1.v1.accounts.models.user import User
from apiV1.v1.accounts.serializers.user import UserSerializerLogin
# login
class LoginView(APIView):
authentication_classes = ()
permission_classes = ()
#staticmethod
def post(request):
"""
Get user data and API token
"""
user = get_object_or_404(User, email=request.data.get('email'))
user = authenticate(username=user.email, password=request.data.get('password'))
if user:
serializer = UserSerializerLogin(user)
return Response(serializer.data)
return Response(status=status.HTTP_400_BAD_REQUEST)
If you don't need session for authentication you have to use token authentication.
Here is the example of view
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.response import Response
class Login(ObtainAuthToken):
def post(self, request, *args, **kwargs):
"""
---
serializer: AuthTokenSerializer
"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'pk': user.pk,
'first_name': user.first_name,
'last_name': user.last_name,
})
Or you can use JWT authentication.
Here are some helpful links for you.
http://www.django-rest-framework.org/api-guide/authentication/
http://getblimp.github.io/django-rest-framework-jwt/

Disable All Authentication Django

I have an API written in Django, with authentication with cookie and sessionid.
Now I want to add a end-point public, with any kind of authentication, but I can't access the end-point.
What I've done:
URL:
url(r'^api/public_end_point/?$', csrf_exempt(views.publicEndPoint.as_view()), name='public_end_point')
Views:
class publicEndPoint(APIView):
#api_view(['POST'])
#permission_classes([permissions.AllowAny,])
def post(self, request, *args, **kwargs):
return Response({"success": True, "content": "Hello World!"})
Some Ideas about what am I missing here ?
Thanks
EDIT
Settings:
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',
# MY MIDDLEWARE #
'config.middleware.EnforceLoginMiddleware',
'config.middleware.AuditMiddleware',
'config.middleware.ExceptionMiddleware',
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
'PAGE_SIZE': 20
}
[15/Feb/2017 15:57:16] "POST /api/public_end_point HTTP/1.1" 302 0
[15/Feb/2017 15:57:16] "GET /sign/base.html?nu=/api/public_end_point HTTP/1.1" 200 2906
Just add PERMISSION_CLASSES = (,) to your view as class variable, you don't need to use a decorator.
Just for informational purposes - Django Rest Framework by default uses BasicAuthentication and SessionAuthentication such that you either need to be logged in or provide Basic authentication credentials to access the api.
If you need your own custom token authentication, you need to override AUTHENTICATION_CLASSES in your drf settings.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
# add your own authentication class
)
}

django's not working when implement a custom middleware to check whether user is active and check if user is login then it can be enter in the site

django's not working when implement a custom middleware to check whether user is active and check if user is login then it can be enter in the site otherwise it will back to the login page
my middleware is i just try to implement that for check if user is not login then it can not enter in to site
from django.shortcuts import render, redirect
from django.contrib.auth.forms import AuthenticationForm
class FilterMiddleware(object):
# Check if client is allowed
def process_request(self, request):
if not request.user.is_authenticated() :
form_class = AuthenticationForm
template_name = 'music/login_form.html'
form = form_class(None)
return render(request, template_name, {'form': form})
return super(FilterMiddleware, self).dispatch(request)
settings.py:
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',
'music.middleware.filter_middleware.FilterMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware'
]
you can also use #login_required decorator to redirect to login page if user is not loggedIn.

Django 1.8 XFrameOptionsMiddleware and xframe_options_exempt decorators not working

I have a website I have built in Django 1.8 which must load in a Box.com iframe. However it is not loading in Chrome and I get the x-frame-options SAMEORIGIN error.
But I have added the following middleware classes:
MIDDLEWARE_CLASSES = (
# Default Django middleware.
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
and in my views.py added the xframe_options_exempt decorator like so:
#api_view(['GET'])
#xframe_options_exempt
def category_list(request):
"""
List all categories.
"""
if request.method == 'GET':
categories = Category.objects.order_by('-category_type')
serializer = CategorySerializer(categories, many=True)
return Response(serializer.data)
Plus I have tried adding the following setting with no luck:
X_FRAME_OPTIONS = 'ALLOW-FROM https://app.box.com/'
Can anyone help me discover why this is still not allowing the page to load?
Do I also need to add the decorator function in urls.py like this?
from django.views.decorators.clickjacking import xframe_options_exempt
urlpatterns = patterns('base.views',
url(r'^categories$', xframe_options_exempt(category_list)),
)
Thanks very much for any help.