funkifunki
funkifunki

Reputation: 1169

ApiKey authentication in tastypie with mongoengine

Has anybody had success implementing ApiKey for User from mongoengine.django.auth for use with tastypie ApiKeyAuthentication?

I'm aware of the previous posts on the matter, but they address ORM only, while i'm trying to set it up for mongoengine. Also, it seems that tastypie's own ApiKey class heavily relies on relational structure (using related field api_key of User)

thanks in advance!

Upvotes: 0

Views: 308

Answers (1)

funkifunki
funkifunki

Reputation: 1169

following this thread https://github.com/mitar/django-tastypie-mongoengine/issues/25 i've created MongoUser class with api_key field

# models.py (or documents.py)
from mongoengine.django.auth import User

class MongoUser(User):
    """
    Subclass of mongoengine.django.auth.User with email as username
    and API key for authentication.
    """
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['password']

    api_key = StringField(max_length=256, default='')
    api_key_created = DateTimeField(help_text=_(u'Created'))

    def save(self, *args, **kwargs):
        if not self.api_key:
            self.set_api_key()

        return super(MongoUser, self).save(*args, **kwargs)

    def set_api_key(self):
        self.api_key = self.generate_key()
        self.api_key_created = datetime.now()

    def generate_key(self):
        new_uuid = uuid.uuid4()
        return hmac.new(str(new_uuid), digestmod=sha1).hexdigest()

added a signal (the usual):

# resources.py
from mongoengine import signals
from myapp import models
signals.post_save.connect(create_api_key, sender=models.MongoUser)

and then subclassed tastypie.ApiKeyAuthentication with the following:

# resources.py
class CustomApiKeyAuthentication(ApiKeyAuthentication):
    """
    Authenticates everyone if the request is GET otherwise performs
    ApiKeyAuthentication.
    """
    def is_mongouser_authenticated(self, request):
        """
        Custom solution for MongoUser ApiKey authentication.
        ApiKey here is not a class (as it is realized in ORM approach),
        but a field MongoUser class.
        """
        username, api_key = super(CustomApiKeyAuthentication,
                                  self).extract_credentials(request)
        try:
            models.MongoUser.objects.get(username=username, api_key=api_key)
        except models.MongoUser.DoesNotExist:
            return False

        return True

    def is_authenticated(self, request, **kwargs):
        """
        Custom solution for `is_authenticated` function: MongoUsers has got
        authenticated through custom api_key check.
        """
        if request.method == 'GET':
            return True
        try:
            is_authenticated = super(CustomApiKeyAuthentication,
                                     self).is_authenticated(request, **kwargs)
        except TypeError as e:
            if "MongoUser" in str(e):
                is_authenticated = self.is_mongouser_authenticated(request)
            else:
                is_authenticated = False
        return is_authenticated

Upvotes: 1

Related Questions