1
votes

When I try to do request.user.is_authenticated() I get a ValidationError: None is not a valid ObjectId

I'm trying to track down the problem but I do not what's causing it.I'm using MongoEngine (and MongoDB.)

I have the following in my settings.py:

AUTHENTICATION_BACKENDS = (
    'mongoengine.django.auth.MongoEngineBackend',
    'rs.claimutil.auth_backend.ClaimAuthBackend',
)


SESSION_ENGINE = 'mongoengine.django.sessions'

This is what I get:

Traceback: File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 111. response = callback(request, *callback_args, **callback_kwargs) File "/Users/bastiano/Documents/ttsf/rsrv/views.py" in reserve 11. if not request.user.is_authenticated(): File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/functional.py" in inner 184. self._setup() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/functional.py" in _setup 248. self._wrapped = self._setupfunc() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in 16. request.user = SimpleLazyObject(lambda: get_user(request)) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in get_user 8. request._cached_user = auth.get_user(request) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/init.py" in get_user 101. user = backend.get_user(user_id) or AnonymousUser() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/django/auth.py" in get_user 149. return User.objects.with_id(user_id) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in with_id 923. return self.filter(pk=object_id).first() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in first 843. result = self[0] File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in getitem 1136. return self._document._from_son(self._cursor[key]) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in _cursor 579. self._cursor_obj = self._collection.find(self._query, File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in _query 375. self._mongo_query = self._query_obj.to_query(self._document) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in to_query 202. query = query.accept(QueryCompilerVisitor(document)) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in accept 267. return visitor.visit_query(self) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in visit_query 159. return QuerySet._transform_query(self.document, **query.query) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py" in _transform_query 720. value = field.prepare_query_value(op, value) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py" in prepare_query_value 455. return self.to_mongo(value) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py" in to_mongo 451. self.error(unicode(e)) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py" in error 203. raise ValidationError(message, errors=errors, field_name=field_name)

Exception Type: ValidationError at /rs/claim Exception Value: None is not a valid ObjectId

Any ideas why this is happening? Is there an easier way to do user authentication in Django + MongoDB?

Views.py:

def claim(request):
    if request.method == 'GET':
        if not request.user.is_authenticated():
            return shortcuts.redirect('rs/login')
        all_b = dbutil.get_b(all=True)
        return shortcuts.render_to_response('rs/index.html',
                                             {'all_b':all_b},
                                            context_instance=template.RequestContext(request))
    elif request.method == 'POST':

The rest of the view is omitted for simplicity. I used ipdb to debug it and if not request.user.is_authenticated() is the problem. I tried using django.contrib.auth.decorators.login_required.decorator before, but it, too, failed.

3
The problem was that Django was using mongoengine.django.auth.MongoEngineBackendand not the authentication backend I created. Even though I specified it in settings.py, I had the following line in one of my views: r_v.obj.backend = 'mongoengine.django.auth.MongoEngineBackend', this, of course, forces Django to use that authentication backend. @Ross and @okm, thank you!sebastian

3 Answers

2
votes

Try to update your mongoengine to the latest version. In master, it is

def get_user(userid):
    """Returns a User object from an id (User.id). Django's equivalent takes
    request, but taking an id instead leaves it up to the developer to store
    the id in any way they want (session, signed cookie, etc.)
    """
    # your installed mongoengine might not include following two lines
    if not userid:
        return AnonymousUser()
    return MongoEngineBackend().get_user(userid) or AnonymousUser()

A userid w/ value of None causes the problem, according to the trackback.

1
votes

What version of MongoEngine / Django are you using?

Have you enabled the django.contrib.auth.middleware.AuthenticationMiddleware? That should set a User instance or AnonymousUser to the request.

What does rs.claimutil.auth_backend.ClaimAuthBackend look like? And what does its get_user method return? Does it stop erroring if you just have one authentication backend?

1
votes

In one of my views I had the following: r_v.obj.backend = 'mongoengine.django.auth.MongoEngineBackend', which is why Django was ignoring the AUTHENTICATION_BACKENDS in settings.py, and was never using my custom authentication backend.