Saturday, November 17, 2012

A One Time Password Service

One time passwords, unlike regular passwords, can be used only once. They are typically used for authenticating occasional transactions, or alongside some other authentication factor to implement multi-factor authentication. For example, your bank may send an OTP to your mobile phone and require you to punch it in along with your regular password, so as to validate that you know the account password and you also possess the mobile phone that the account holder is supposed to have.

I have implemented and hosted a simple OTP service, using Mashape API provider. The service is a REST service, accessible over HTTP and can be consumed in any way you wish. The service is hosted on my public server and uses Mashape for the passthrough proxy interface. Mashape provides generated code for PHP, Python, Ruby, Java (Android) and Obejctive-C (iOS) to make it super easy to use APIs.

Through this post I'll walk you through using the service using a Python implementation. 

Step 1:

To use the API, you must first register with Mashape and get yourself an account. Once you register, visit the OTP generator API page here to have a look at the details. Download the Python sample implementation from the link on this page and you are ready to start! During the download, you will also be shown your Mashape public and private keys to be used along with the API, copy them somewhere to be used later. Remember to keep your keys safe.


Step 2:

Extract the downloaded sample code on to a folder. Read the README file to make sure you have the dependancies installed.
Open the file sample.py, and paste your public and private keys at the places indicated.


Step 3:

As a first step, you must configure your account with otpgen API server. Configuration involves setting up a shared secret for your account so that no one else can masquerade as you. For the first time, before even you use the configure API, the secret is set to be the same as your public key. You must change it before you can use any other API. The configure API is therefore the first API that must be called. It takes in a secret to be set for your account and a signature.

The signature is part of every API call to otpgen. The signature is a SHA1 hash of all the parameters to the API ordered by their name, along with the shared secret, all separated by a comma. So for example, if you are setting up your account with a secret value of "supersecret" and your account public key is 12345, for the configure API call the signature would be the SHA1 hash of the string "secret,supersecret,12345".

Since you have to do the signing for every API call, let's first define a method to do that. Below is the method that I have implemented:

def sign_request(req_params, secret):
    keys = req_params.keys()
    keys.sort()
    
    kvarr = []
    for key in keys:
        kvarr.append(key)
        kvarr.append(str(req_params.get(key)))
    
    kvarr.append(secret)
    sha = hashlib.sha1()
    sha.update(",".join(kvarr))
    return sha.hexdigest()


Now you can define another method to do the first time secret configuration. Below is the method that I have implemented. Actually I also implemented a simple helper method called unwrap to get the response JSON out of the Mashape wrapped response object.

MY_MASHAPE_PUB_KEY = 'replace this with your public key'
MY_MASHAPE_PRIV_KEY = 'replace this with your private key'

client = Otpgen(MY_MASHAPE_PUB_KEY, MY_MASHAPE_PRIV_KEY)

def unwrap(mashape_resp):
    return (vars(mashape_resp)).get('body')

def configure_first_time(secret):
    req_params = { 'secret': secret }
    sig = sign_request(req_params, MY_MASHAPE_PUB_KEY)
    req_params['sig'] = sig
    
    response = client.configure(**req_params)
    # retrieve the JSON response from the wrapper
    response = unwrap(response)
    return response


Step 4:

Once you have configured our account, you can go ahead and generate one time passwords for users and verify them. While issuing a token, you can set a string as data to be remembered or tagged with this OTP. On successful validation of this OTP, the tagged data will be returned to the validating call.

By now you would have gotten a hang of how to use the API and we have written most of the support functions we had to write for using the API. I have implemented methods issue_otp and validate_otp in my sample. The sample source issues one OTP and verifies it immediately after that. Go ahead and refer to the complete source code here and see how I have implemented it.

To summarize, here are a few quick links:

This implementation should suffice many simple use cases of most applications. If you have any requirement that is not met or ideas that you would like to discuss, please do reach out to me.

No comments: