SegAnnDB Login System

The authentication is pretty basic which can be summed up in the following steps -

  1. User logs in via Google OAuth
  2. The user information is retrieved from Google’s API
  3. Using pyramid, we set a cookie on with the name of user_id
  4. Everytime a request comes in we decode the cookie, and get the user_id
  5. For logout, a simple javascript function clears out the cookie by invalidating it based on expire time.
  6. For retrieving the user_id from the cookie in the server-side I wrote down a simple function which takes the request and retrieves the user_id from the cookie.

Picking up from my last (blog post)[http://abstatic.github.io/session-vs-token-authourization.html] , I was experimenting around with pyramid_google_login for implementing a OAuth2 based login system.

Turns out, pyramid_google_login had some compatibility issues with the version of pyramid we were using in SegAnnDB. So I decided to fork the repo and fixed all the compatibility issues. Added to that I also made some modifications in the code to set cookie in the returning response in case of a successful login.

For handling the logout, I had to rely on javascript because I was not storing any information about the session cookie using pyramid. Here is the JS code that handles the logout functionality -

File: static/auth.js

// check if user is logged in or not
// on basis of that show appropriate buttons
var user = getCookie("authtkt");
var divElem = $("#auth");

if (user != "") 
{
    var button = "<button onclick='bye()'>Log Out</button>";
    divElem.append(button);
}
else
{
  // okay the user is not logged in 
  // render the login button
  var button = "<a href='/auth/signin_redirect'><button>Login</button></a>";
  divElem.append(button);
}

// function to erase cookies
// courtsey StackOverflow :)
// - http://stackoverflow.com/questions/179355/clearing-all-cookies-with-javascript
function eraseCookieFromAllPaths(name) {
    // This function will attempt to remove a cookie from all paths.
    var pathBits = location.pathname.split('/');
    var pathCurrent = ' path=';

    // do a simple pathless delete first.
    document.cookie = name + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT;';

    for (var i = 0; i < pathBits.length; i++) {
        pathCurrent += ((pathCurrent.substr(-1) != '/') ? '/' : '') + pathBits[i];
        document.cookie = name + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT;' + pathCurrent + ';';
    }
}

// function to logout the user
function bye()
{
  eraseCookieFromAllPaths("authtkt");

  //now we need to refresh the page as well.
  location.reload();
}

// function to get a cookie from cookie storage
function getCookie(cname) 
{
  var name = cname + "=";
  var ca = document.cookie.split(';');
  for(var i = 0; i < ca.length; i++)
  {
      var c = ca[i];
      while (c.charAt(0) == ' ')
      {
          c = c.substring(1);
      }
      if (c.indexOf(name) == 0) 
      {
          return c.substring(name.length, c.length);
      }
  }
  return "";
}

I also had to override a default pyramid function in file views.py

# I am trying to override the authenticated_userid function here
# retrieve the cookie and return to the user
def authenticated_userid(request):
    """This function returns the user_id from the request"""
    try:
        val = request.cookies["authtkt"]
    except:
        # in case the cookie is not found it applies, unauthenticated user
        val = None;
    print val
    return val

Now as mentioned earlier, I had to find a way to upload my modified version of the login module of pyramid_google_login to pypi so that it can be used in SegAnnDB

For that, I refractored all the code of pyramid_google_login into a new module named seganndb_login. It lives in github and pypi as well.

I also added a cookie based authentication mechanism into the module, and uploaded it to PyPi. We install the new login module using pip install seganndb_login and easily import it into pyramid configuration file.

Using seganndb_login module can be easily used in any other login application too. You only need to install it and add it in your configuration file of pyramid using - config.include('seganndb-login')

The next post will be about creating a container for SegAnnDB both for the old version and the new GSoC code.

Comments