[kwlug-disc] Django API authentication

Paul Nijjar paul_nijjar at yahoo.ca
Sun Aug 23 18:34:15 EDT 2015


On Fri, Aug 14, 2015 at 01:16:47PM -0700, Jotham Apaloo wrote:
> I am also very curious to see if anyone has a simple solution for this. I
> have recently been considering flask/pyramid vs django. For RESTful
> services, django seems *very* cumbersome... perhaps someone can demonstrate
> otherwise.

I don't know that I came up with a simple solution, but I am partway
to something that works. Details below: 

> 
> > My goals:
> >
> > - Authenticate the API methods against a small set of shared
> >   passwords NOT stored on the LDAP server

Setting up multiple authentication databases is not hard. In
settings.py: 

AUTHENTICATION_BACKENDS = (
  'django_auth_ldap.backend.LDAPBackend', 
  'django.contrib.auth.backends.ModelBackend',
)  

will use LDAPBackend first, and then ModelBackend. 

Then in the admin interface I can create local users "desktop_client"
and give them passwords. 


> > - Do it in such a way that it is easy to program the Javascript
> >   snippet and desktop application to authenticate

I have not gotten the Javascript authentication working (and I might
not bother) but I used the Python Requests library to authenticate to
the Django app. The basic idea is that you have to log into the
application as if it was the web interface (GETting the login page and
then POSTing a username and password). Adding SSL to the mix cost me
hours and hours, but I have something working now. 

        self.api_session = requests.Session()

        # http://stackoverflow.com/questions/24562590/login-to-webpage-from-script-using-requests-and-django

        # Terrible hack becuase my cert doesn't have their 
        # naming standards and I don't care. 
        requests.packages.urllib3.disable_warnings(SecurityWarning)

        r_get = self.api_session.get(self.API_LOGIN_URL, 
            verify=self.SERVER_CERT)

        # Set required data for the POST request
        csrftoken = self.api_session.cookies['csrftoken']
        data = {
            "username": self.API_LOGIN_NAME, 
            "password": self.API_LOGIN_PASS,
            "csrfmiddlewaretoken": csrftoken,
            }
        # Gah. You set the HEADER, not the data. 
        # You need this because Django checks the referer
        headers = { 
            "Referer" : r_get.url,
            }

        r_post = self.api_session.post(self.API_LOGIN_URL, data=data, 
            headers=headers, verify=self.SERVER_CERT)


At this point self.api_session has an authentication cookie, and you
can make other API calls without further logins. 


> > - Do it quickly and easily, without needing to learn anything too
> >   complex (otherwise I would just use Tastypie)

I claim the fifth on this. I did read a lot about how the Requests
library was awesome, so I switched to it from urllib. 

> > - Not use this layer of authentication for the interactive screens of
> >   the webapp

In some ways this is not true, since regular interactive users also
have to log in. Thus the authentication mechanisms are the same. But
the burden on interactive users is no worse, which was my goal.

I did use Django groups and login decorators to ensure that the API
account could not access the interactive screens. 

Being both a Python/Django newbie and a terrible programmer, 
I am sure this code is awful and will get me burned at the stake, so
use it with caution. 


- Paul 


-- 
http://pnijjar.freeshell.org





More information about the kwlug-disc mailing list