r4fek / django-cassandra-engine

Django Cassandra Engine - the Cassandra backend for Django
BSD 2-Clause "Simplified" License
365 stars 84 forks source link

AuthenticationBackend not working #48

Open EzequielAdrianM opened 8 years ago

EzequielAdrianM commented 8 years ago

Supposing that Sessions are not a problem (no database involved), our session backend could be Cache or Signed Cookies.

When I am trying to authenticate a User, the authentication backend does not recognize the Cassandra-based User Model. Probably because it was not created with

from django.contrib.auth.models import AbstractBaseUser

This is my models.py:

from cassandra.cqlengine import columns
from cassandra.cqlengine import models

class User(models.Model):
    username = columns.Text(primary_key=True)
    password = columns.Text()
    email = columns.Text()
    fullname = columns.Text()
    is_staff = columns.Boolean(default=False)

My views.py:

from django.shortcuts import render
from django.http import HttpResponse
from forms import LoginForm
from django.views.generic import View

class Login(View):
    def get(self, request):
        if request.user.is_authenticated():
            return HttpResponse("ALREADY LOGGED IN")
        else:
            template = "login.html"
            loginform = LoginForm()
            return render(request, template, {'loginform': loginform})

Obviously, I can't log a user in... so request.user will always return AnonymousUser.???

The question is, what can I do to make Django authenticate users correctly and make request.user return User instance?

I will help you to contribute, but I need some clues...

r4fek commented 8 years ago

Thanks for the report @EzequielAdrianM. For now I would recommend using regular relational database for storing users and cassandra as secondary backend.

Unfortunately authentication does not work yet with django_cassandra_engine backend, but this is on my TODO list.

EzequielAdrianM commented 8 years ago

Hi @r4fek I have managed to make my Django project work with Cassandra as the unique database backend. But my solution is temporal since I still ignore "request.user.is_authenticated()". I had to write my own SessionBackend for Cassandra and It works excellent ! The bad thing is that I am NOT using Django Authentication System but thanks to the "Modularity" of Django I use my custom SessionBackend to obtain and decode the SessionData and, check, whether a user is Authenticated or not.

r4fek commented 8 years ago

@EzequielAdrianM and now session backend is included in latest dce! You can try it by yourself. We're one step closer to have working auth system based on Cassandra.

EzequielAdrianM commented 8 years ago

Hi, I have seen your update, but now I have migrated completely to Cassandra. Including the User tables. So I wanted to share with you my Fast Fix implementation. And what do you think about it.

from django.conf import settings from django.utils.encoding import force_unicode from django.contrib.sessions.backends.base import SessionBase, CreateError from datetime import datetime from datetime import timedelta import cass

class SessionStore(SessionBase):
    """
    A Cassandra based session store.
    """
    def load(self):
        try:
            #GET SESSIONDATA BASED ON SESSIONKEY
            data = cass.get_session(self.session_key)
            #NOW
            a = datetime.now()
            #EXPIRE-DATE - NOW = TIME-LEFT
            c = data['expire_date'] - a
            if c.total_seconds() > 0:
                return self.decode(force_unicode(data['session_data']))
            #Manually remove session from DB
            cass.remove_session(session_key)
            self._session_key = None
            return {}
        except cass.DatabaseError:
            self._session_key = None
            return {}

    def create(self):
        while True:
            self._session_key = self._get_new_session_key()
            try:
                # Save immediately to ensure we have a unique entry in the database
                self.save(must_create=True)
            except CreateError:
                # Key wasn't unique. Try again.
                continue
            self.modified = True
            return

    def save(self, must_create=False):
        if self.session_key is None:
            return self.create()

        if must_create and self.exists(self.session_key):
            raise CreateError
        else:
            #DJANGO GENERATES NEW SESSION_DATA
            session_data = self.encode(self._get_session(no_load=must_create))
            #NOW + EXPIRY SECONDS = EXPIRE-DATE
            expire_date = datetime.now() + timedelta(seconds=self.get_expiry_age())
            #STRIP MICROSECONDS
            expire_date = expire_date.strftime("%Y-%m-%d %H:%M:%S")
            #ADD TIMEZONE
            expire_date = expire_date + '+0000'

            cass.create_session(self.session_key, session_data, expire_date)

    def exists(self, session_key):
        #CHECK IF SESSION_KEY EXISTS...
        return cass.check_session_existence(session_key)

    def delete(self, session_key=None):
        if session_key is None:
            if self.session_key is None:
                return
            session_key = self.session_key
        cass.remove_session(session_key)

And cass.py (Partially Taken from Twissandra Project, which is now deprecated)

from django.db import connection cursor = connection.cursor()

# EXCEPTIONS
class DatabaseError(Exception):
    """
    The base error that functions in this module will raise when things go
    wrong.
    """
    pass
class NotFound(DatabaseError): pass
class InvalidDictionary(DatabaseError): pass

#COOKIES SESSION OPERATIONS
def create_session(session_key, session_data, expire_date):
    cursor.execute("INSERT INTO sessions (session_key, session_data, expire_date) VALUES ('%s', '%s', '%s')" % (session_key, session_data, expire_date));
    return True

def check_session_existence(session_key):
    result = cursor.execute("SELECT session_key FROM sessions WHERE session_key = '%s'" % session_key);
    if not result:
        return False
    return True

def remove_session(session_key):
    cursor.execute("DELETE FROM sessions WHERE session_key = '%s'" % session_key);
    return True

def get_session(session_key):
    result = cursor.execute("SELECT session_data, expire_date FROM sessions WHERE session_key = '%s'" % session_key);
    if not result:
        raise DatabaseError()
    return result[0]
SoumiBera commented 4 years ago

@EzequielAdrianM Can you please provide the entire solution? I have one cassandra User table. And i am trying to create session-key for that particular user.