http://en.wikipedia.org/wiki/One-time_password, thanks Madhukar R Pai
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 1.99.4 (2012-01-29 15:21:17) stable
|
Version 1.99.4 (2012-01-29 15:22:07) stable
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import time
|
||||||
|
from hashlib import md5
|
||||||
|
from gluon.dal import DAL
|
||||||
|
|
||||||
|
def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
||||||
|
time_offset=60):
|
||||||
|
|
||||||
|
"""
|
||||||
|
motp allows you to login with a one time password(OTP) generated on a motp client,
|
||||||
|
motp clients are available for practically all platforms.
|
||||||
|
to know more about OTP visit http://en.wikipedia.org/wiki/One-time_password
|
||||||
|
to know more visit http://motp.sourceforge.net
|
||||||
|
|
||||||
|
|
||||||
|
Written by Madhukar R Pai (madspai@gmail.com)
|
||||||
|
License : MIT or GPL v2
|
||||||
|
|
||||||
|
thanks and credits to the web2py community
|
||||||
|
|
||||||
|
to use motp_auth:
|
||||||
|
motp_auth.py has to be located in gluon/contrib/login_methods/ folder
|
||||||
|
first auth_user has to have 2 extra fields - motp_secret and motp_pin
|
||||||
|
for that define auth like shown below:
|
||||||
|
|
||||||
|
## after auth = Auth(db)
|
||||||
|
db.define_table(
|
||||||
|
auth.settings.table_user_name,
|
||||||
|
Field('first_name', length=128, default=''),
|
||||||
|
Field('last_name', length=128, default=''),
|
||||||
|
Field('email', length=128, default='', unique=True), # required
|
||||||
|
Field('password', 'password', length=512, # required
|
||||||
|
readable=False, label='Password'),
|
||||||
|
Field('motp_secret',length=512,default='',
|
||||||
|
label='MOTP Seceret'),
|
||||||
|
Field('motp_pin',length=128,default='',
|
||||||
|
label='MOTP PIN'),
|
||||||
|
Field('registration_key', length=512, # required
|
||||||
|
writable=False, readable=False, default=''),
|
||||||
|
Field('reset_password_key', length=512, # required
|
||||||
|
writable=False, readable=False, default=''),
|
||||||
|
Field('registration_id', length=512, # required
|
||||||
|
writable=False, readable=False, default=''))
|
||||||
|
|
||||||
|
##validators
|
||||||
|
custom_auth_table = db[auth.settings.table_user_name] # get the custom_auth_table
|
||||||
|
custom_auth_table.first_name.requires = \
|
||||||
|
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
||||||
|
custom_auth_table.last_name.requires = \
|
||||||
|
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
||||||
|
custom_auth_table.password.requires = CRYPT()
|
||||||
|
custom_auth_table.email.requires = [
|
||||||
|
IS_EMAIL(error_message=auth.messages.invalid_email),
|
||||||
|
IS_NOT_IN_DB(db, custom_auth_table.email)]
|
||||||
|
|
||||||
|
auth.settings.table_user = custom_auth_table # tell auth to use custom_auth_table
|
||||||
|
## before auth.define_tables()
|
||||||
|
|
||||||
|
##after that:
|
||||||
|
|
||||||
|
from gluon.contrib.login_methods.motp_auth import motp_auth
|
||||||
|
auth.settings.login_methods.append(motp_auth(db=db))
|
||||||
|
|
||||||
|
##Instructions for using MOTP
|
||||||
|
- after configuring motp for web2py, Install a MOTP client on your phone (android,IOS, java, windows phone, etc)
|
||||||
|
- initialize the motp client (to reset a motp secret type in #**#),
|
||||||
|
During user creation enter the secret generated during initialization into the motp_secret field in auth_user and
|
||||||
|
similarly enter a pre-decided pin into the motp_pin
|
||||||
|
- done.. to login, just generate a fresh OTP by typing in the pin and use the OTP as password
|
||||||
|
|
||||||
|
###To Dos###
|
||||||
|
- both motp_secret and pin are stored in plain text! need to have some way of encrypting
|
||||||
|
- web2py stores the password in db on successful login (should not happen)
|
||||||
|
- maybe some utility or page to check the otp would be useful
|
||||||
|
- as of now user field is hardcoded to email. Some way of selecting user table and user field.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def verify_otp(otp,pin,secret,offset=60):
|
||||||
|
epoch_time = int(time.time())
|
||||||
|
time_start = int(str(epoch_time - offset)[:-1])
|
||||||
|
time_end = int(str(epoch_time + offset)[:-1])
|
||||||
|
for t in range(time_start-1,time_end+1):
|
||||||
|
to_hash = str(t)+secret+pin
|
||||||
|
hash = md5(to_hash).hexdigest()[:6]
|
||||||
|
if otp == hash: return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def motp_auth_aux(email,
|
||||||
|
password,
|
||||||
|
db=db,
|
||||||
|
offset=time_offset):
|
||||||
|
if db:
|
||||||
|
user_data = db(db.auth_user.email == email ).select().first()
|
||||||
|
if user_data:
|
||||||
|
if user_data['motp_secret'] and user_data['motp_pin']:
|
||||||
|
motp_secret = user_data['motp_secret']
|
||||||
|
motp_pin = user_data['motp_pin']
|
||||||
|
otp_check = verify_otp(password,motp_pin,motp_secret,offset=offset)
|
||||||
|
if otp_check: return True
|
||||||
|
else: return False
|
||||||
|
else: return False
|
||||||
|
return False
|
||||||
|
return motp_auth_aux
|
||||||
Reference in New Issue
Block a user