0

I am trying to use Django with a non-ORM data source, and while accessing other resources through my custom backend without any authentication is successful, now I need to introduce user authentication. There is no local database. When I receive a request (e.g., a cURL command made with username and password), I need to perform HTTP Basic Authentication against a remote URL and upon success, I should return a locally created user object, which only has a username, nothing fancy. So in my Tastypie resource, I wrote something like this:

class dict2obj(object):
    """
    Convert dictionary to object
    @source http://stackoverflow.com/a/1305561/383912
    """
    def __init__(self, d):
        self.__dict__['d'] = d

    def __getattr__(self, key):
        value = self.__dict__['d'][key]
        if type(value) == type({}):
            return dict2obj(value)
        return value


class RemoteAuth(Authentication):
    def is_authenticated(self, request, **kwargs):
        username = request.user.username
        password = request.user.password
        r = requests.get(AUTHENTICATION_URL, auth=(username, password))
        if r.status_code == 200:
          return True
        return False



class UserResource(Resource):             
    username = fields.CharField(attribute='username')

    class Meta:
        resource_name = 'user'
        authentication = RemoteAuth()
        authorization = Authorization()

        def obj_get_list(self, request=None, **kwargs):

            result = []

            posts.append(dict2obj(
            {
            'username': request.POST.get('username'),
            }
            ))

            return result   

But of course this does not work, because the authentication object cannot obtain password like that. Please suggest a good way of handling remove user authentication without involving any local database.

Subhamoy S.
  • 6,566
  • 10
  • 37
  • 53
  • Have you tried storing the `username` and `password` in `session` after successful request to your login endpoint? You could serve the login API via SSL to make it a little more secure. – Maciej Gol Oct 09 '13 at 15:15
  • I am not sure how that is to be done. Could you point me to some sample code? I was under the impression that a Tastypie resource is an endpoint. I am trying to access `http://localost:8000/api/v1/user/?format=json` – Subhamoy S. Oct 09 '13 at 15:26
  • I will submit it as a separate answer, as it is difficult to include inline code in comments – Maciej Gol Oct 09 '13 at 15:30
  • Looking forward to it :) – Subhamoy S. Oct 09 '13 at 15:36

1 Answers1

0

If you would like to have user authentication without storing any actual data on your side, then you could use session or, as last resort, cookies. The session data could be encrypted and stored inside the session cookie itself, or a side cookie.

How that would work?

You could create an endpoint, say api/v1/user/login, as the UserResource method to handle user authentication/login. You can do so like this:

def override_urls(self):
    return [
        url(r"^(?P<resource_name>%s)/login%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('user_login'), name="api_user_login"),
    ]

def user_login(self, request, **kwargs):
    # Authentication process happens here.
    return self.create_response(request, {})

For the above to work, you have to import tastypie.utils.trailing_slash and django.conf.urls.url. Unfortunately, tastypie doesn't support any helper method to creating urls less painfully.

In the user_login method, you would then authenticate credentials passed via POST against the remote endpoint and store the username and password in the request.session along with any remote-authentication-endpoint-specific data. In the RemoteAuthentication you could then check for the session keys existence.

If the session is data in your local filesystem, then the data inside can be considered a little more secure. If you decide to store the session data in an encrypted cookie, you would have to store a value and a checksum for each session key, possibly in a single cookie entry, or seperate ones.

Since the users would be passing their credentials in plain text to login, you could consider serving the user_login view via SSL (make sure the cookie is not secure_only then).

Maciej Gol
  • 15,394
  • 4
  • 33
  • 51
  • But the reason I want BasicAuthentication on the whole resource is that I do not want to stay logged in. Random requests will be made using cURL or Jquery/Ajax on methods of a resource. Every request will be made with username and password, not necessarily the same one every time. – Subhamoy S. Oct 09 '13 at 15:59
  • 1
    Then you can pass username and password in custom headers, i.e. `X-MYAPP-ID` and `X-MYAPP-PASSWORD` and get those values from `request.META` in your `RemoteAuthentication` and authenticate the user against the remote service – Maciej Gol Oct 09 '13 at 16:02