I want to generate a password reset token for a User model that I have with Google App Engine. Apparently we're not allowed to use Django that easily with GAE, so the raw code for the Django method for generating tokens is:
def _make_token_with_timestamp(self, user, timestamp):
# timestamp is number of days since 2001-1-1. Converted to
# base 36, this gives us a 3 digit string until about 2121
ts_b36 = int_to_base36(timestamp)
# By hashing on the internal state of the user and using state
# that is sure to change (the password salt will change as soon as
# the password is set, at least for current Django auth, and
# last_login will also change), we produce a hash that will be
# invalid as soon as it is used.
# We limit the hash to 20 chars to keep URL short
key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
# Ensure results are consistent across DB backends
login_timestamp = user.last_login.replace(microsecond=0, tzinfo=None)
value = (unicode(user.id) + user.password +
unicode(login_timestamp) + unicode(timestamp))
hash = salted_hmac(key_salt, value).hexdigest()[::2]
return "%s-%s" % (ts_b36, hash)
Python is not my language of expertise, so I'll need some help writing a custom method similar to the one above. I just have a couple questions. First, what is the purpose of the timestamp? And Django has its own User system, while I'm using a simple custom User model of my own. What aspects from the above code will I need to retain, and which ones can I do away with?
well, the check_token-method looks like this:
def check_token(self, user, token):
"""
Check that a password reset token is correct for a given user.
"""
# Parse the token
try:
ts_b36, hash = token.split("-")
except ValueError:
return False
try:
ts = base36_to_int(ts_b36)
except ValueError:
return False
# Check that the timestamp/uid has not been tampered with
if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
return False
# Check the timestamp is within limit
if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
return False
return True
first the timestamp part of the token is converted back to integer
then a new token is generated using that timestamp and compared to the old token. Note that when generating a token the timestamp of the last login is one of the parameters used to calculate the hash. That means that after a user login the old token would become invalid, which makes sense for a password reset token.
lastly a check is performed to see if the token hasn't alerady timed out.
it's a fairly simple process, and also fairly secure. If you wanted to use the reset-system to break into an account, you'd have to know the user's password and last login timestamp to calculate the hash. And if you knew that wouldn't need to break into the account...
So if you want to make a system like that, it's important when generating the hast to use parameters that are not easy to guess, and of course to use a good, salted hash function. Django uses sha1, using other hashlib digests would of course be easily possible.
Another way would be to generate a random password reset token and store it in the database, but this potentially wastes a lot of space as the token-column would probably be empty for most of the users.
Related
Is there a way to check if the user is blocked like an is_blocked method? The way I have it set up right now is to get a list of my blocked users and comparing the author of a Tweet to the list, but it's highly inefficient, as it constantly runs into the rate limit.
Relevent Code:
blocked_screen_names = [b.screen_name for b in tweepy.Cursor(api.blocks).items()]
for count, tweet in enumerate(tweepy.Cursor(api.search, q = query, lang = 'en', result_type = 'recent', tweet_mode = 'extended').items(500)):
if tweet.user.screen_name in blocked_screen_names:
continue
No, you'll have to do that the way you're currently doing it.
(Also, just a side note, you're better off checking your blocked users via their account ID rather than their screen name, because this value will not change, whereas a user's screen name can)
For future reference, just check the Twitter API documentation, where you can get the answer for something like this straight away :) save yourself the waiting for someone to answer it for you here!
You'll notice that both the documentation for V1 and V2 do not contain an attribute as you have described:
V1 User Object:
https://developer.twitter.com/en/docs/twitter-api/v1/data-dictionary/object-model/tweet
V2 User Object:
https://developer.twitter.com/en/docs/twitter-api/data-dictionary/object-model/user
Handle the error while making a connection, below code is not working, tried with incorrect names and password still not giving any error
block_blob_service = BlockBlobService(account_name = account_name,account_key = account_key)
try:
if block_blob_service:
print('connection successful!')
except Exception as e:
print('Please make sure the account name and key are correct.', e)
Following line of code:
block_blob_service = BlockBlobService(account_name = account_name,account_key = account_key)
is actually creating an instance of BlockBlobService (not sure if creating instance is the correct term :), coming from .Net world) and nothing else.
In order to check if the account name/account key combination is correct, you will actually need to perform an operation on that storage account as there is no Login kind of operation supported in Azure Storage.
Normally the way I do it is try to list blob containers from that storage account. When listing blob containers, just set the num_results parameter to 1 as we are only interested in checking the account name/key validity and nothing else.
There are three possible outcomes:
Account name/key is correct: In this case you would not get any errors.
Account name is incorrect: In this case you will get remote name could not be resolved error.
Account key is incorrect: In this case you will get a 403 error back from the service.
Using these outcomes you can decide whether or not account name/key combination is valid.
I want some search feature in my website. In the output page, I am getting all the results in single page. However, I want to distribute it to many pages (i.e. 100 searches/page). For that, I am passing a number of default searches in "urlfor" but it isn't working. I know I am making a small error but I am not catching it.
Here is my code below:
#app.route('/', methods=['GET', 'POST'])
def doSearch():
entries=None
error=None
if request.method=='POST':
if request.form['labelname']:
return redirect(url_for('show_results',results1='0-100', labelname=request.form['labelname'] ))
else:
error='Please enter any label to do search'
return render_template('index.html',entries=entries, error=error)
#app.route('/my_search/<labelname>')
def show_results(labelname=None, resultcount=None, results1=None):
if not session.get('user_id'):
flash('You need to log-in to do any search!')
return redirect(url_for('login'))
else:
time1=time()
if resultcount is None:
total_count=g.db.execute(query_builder_count(tablename='my_data',nametomatch=labelname, isextension=True)).fetchall()[0][0]
limit_factor=" limit %s ,%s"%(results1.split('-')[0],results1.split('-')[1])
nk1=g.db.execute(query_builder(tablename='my_data',nametomatch=labelname, isextension=True) + limit_factor)
time2=time()
entries=[]
maxx_count=None
for rows in nk1:
if maxx_count is None:
maxx_count=int(rows[0])
entries.append({"xmlname":rows[1],'xmlid':rows[2],"labeltext":rows[12]})
return render_template('output.html', labelname=labelname,entries=entries, resultcount=total_count, time1=time2-time1, current_output=len(entries))
Here I want output on the URL like "http://127.0.0.1:5000/my_search/assets?results1=0-100"
Also, if I edit the url address in browser like I want the next 100 result I can get it on "http://127.0.0.1:5000/my_search/assets?results1=100-100"
Note: here I am using sqlite as backend; so I will use "limit_factor" in my queries to limit my results. And "query_builder" and "query_builder_count" are just simple functions that are generating complex sql queries.
but the error I am getting is "NoneType" can't have split. It stopped at "limit_factor".
Here limit factor is just one filter that I have applied; but I want to apply more filters, for example i want to search by its location "http://127.0.0.1:5000/my_search/assets?results1=0-100&location=asia"
Function parameters are mapped only to the route variables. That means in your case, the show_results function should have only one parameter and that's labelname. You don't even have to default it to None, because it always has to be set (otherwise the route won't match).
In order to get the query parameters, use flask.request.args:
from flask import request
#app.route('/my_search/<labelname>')
def show_results(labelname=None):
results1 = request.args.get('results1', '0-100')
...
Btw, you better not construct your SQL the way you do, use placeholders and variables. Your code is vulnerable to SQL injection. You can't trust any input that comes from the user.
The correct way to do this depends on the actual database, but for example if you use MySQL, you would do this (not that I'm not using the % operator):
sql = ".... LIMIT %s, %s"
g.db.execute(sql, (limit_offset, limit_count))
I have a python script which is using htpasswd authentication. I wish to modify the script depending on the user who has logged in currently. This application is web-enabled. eg.
if current_username = 'ABC':
m = 2
elif current_username = 'PQE':
m = 4
else:
m = 6
Any of the user can log in any time / simultaneously. Want the simplest and most efficient solution. Can anybody help? How do I know which of the user has logged in at any point of time? import getpass getpass.getuser() in the script ?
If you are looking to retrieve a value for specific usernames, you could use a dictionary to store the mapping between username and value. For example, your code above could be rewritten:
username_mapping = {"ABC": 2, "PQE": 4}
# The second argument to get will be returned if the key could not be found
# in the dictionary
m = username_mapping.get(current_username, 6)
For a larger system, you might want to look into a distributed key value store (redis would be a good place to start).
I am trying to use one-time passwords that can be generated using Google Authenticator application.
What Google Authenticator does
Basically, Google Authenticator implements two types of passwords:
HOTP - HMAC-based One-Time Password, which means the password is changed with each call, in compliance to RFC4226, and
TOTP - Time-based One-Time Password, which changes for every 30-seconds period (as far as I know).
Google Authenticator is also available as Open Source here: code.google.com/p/google-authenticator
Current code
I was looking for existing solutions to generate HOTP and TOTP passwords, but did not find much. The code I have is the following snippet responsible for generating HOTP:
import hmac, base64, struct, hashlib, time
def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
if intervals_no == None:
intervals_no = int(time.time()) // 30
key = base64.b32decode(secret)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, digest_mode).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
The problem I am facing is that the password I generate using the above code is not the same as generated using Google Authenticator app for Android. Even though I tried multiple intervals_no values (exactly first 10000, beginning with intervals_no = 0), with secret being equal to key provided within the GA app.
Questions I have
My questions are:
What am I doing wrong?
How can I generate HOTP and/or TOTP in Python?
Are there any existing Python libraries for this?
To sum up: please give me any clues that will help me implement Google Authenticator authentication within my Python code.
I wanted to set a bounty on my question, but I have succeeded in creating solution. My problem seemed to be connected with incorrect value of secret key (it must be correct parameter for base64.b32decode() function).
Below I post full working solution with explanation on how to use it.
Code
The following code is enough. I have also uploaded it to GitHub as separate module called onetimepass (available here: https://github.com/tadeck/onetimepass).
import hmac, base64, struct, hashlib, time
def get_hotp_token(secret, intervals_no):
key = base64.b32decode(secret, True)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
def get_totp_token(secret):
return get_hotp_token(secret, intervals_no=int(time.time())//30)
It has two functions:
get_hotp_token() generates one-time token (that should invalidate after single use),
get_totp_token() generates token based on time (changed in 30-second intervals),
Parameters
When it comes to parameters:
secret is a secret value known to server (the above script) and client (Google Authenticator, by providing it as password within application),
intervals_no is the number incremeneted after each generation of the token (this should be probably resolved on the server by checking some finite number of integers after last successful one checked in the past)
How to use it
Generate secret (it must be correct parameter for base64.b32decode()) - preferably 16-char (no = signs), as it surely worked for both script and Google Authenticator.
Use get_hotp_token() if you want one-time passwords invalidated after each use. In Google Authenticator this type of passwords i mentioned as based on the counter. For checking it on the server you will need to check several values of intervals_no (as you have no quarantee that user did not generate the pass between the requests for some reason), but not less than the last working intervals_no value (thus you should probably store it somewhere).
Use get_totp_token(), if you want a token working in 30-second intervals. You have to make sure both systems have correct time set (meaning that they both generate the same Unix timestamp in any given moment in time).
Make sure to protect yourself from brute-force attack. If time-based password is used, then trying 1000000 values in less than 30 seconds gives 100% chance of guessing the password. In case of HMAC-based passowrds (HOTPs) it seems to be even worse.
Example
When using the following code for one-time HMAC-based password:
secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
print i, get_hotp_token(secret, intervals_no=i)
you will get the following result:
1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710
which is corresponding to the tokens generated by the Google Authenticator app (except if shorter than 6 signs, app adds zeros to the beginning to reach a length of 6 chars).
I wanted a python script to generate TOTP password. So, I wrote the python script. This is my implementation. I have this info on wikipedia and some knowledge about HOTP and TOTP to write this script.
import hmac, base64, struct, hashlib, time, array
def Truncate(hmac_sha1):
"""
Truncate represents the function that converts an HMAC-SHA-1
value into an HOTP value as defined in Section 5.3.
http://tools.ietf.org/html/rfc4226#section-5.3
"""
offset = int(hmac_sha1[-1], 16)
binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
return str(binary)
def _long_to_byte_array(long_num):
"""
helper function to convert a long number into a byte array
"""
byte_array = array.array('B')
for i in reversed(range(0, 8)):
byte_array.insert(0, long_num & 0xff)
long_num >>= 8
return byte_array
def HOTP(K, C, digits=6):
"""
HOTP accepts key K and counter C
optional digits parameter can control the response length
returns the OATH integer code with {digits} length
"""
C_bytes = _long_to_byte_array(C)
hmac_sha1 = hmac.new(key=K, msg=C_bytes, digestmod=hashlib.sha1).hexdigest()
return Truncate(hmac_sha1)[-digits:]
def TOTP(K, digits=6, window=30):
"""
TOTP is a time-based variant of HOTP.
It accepts only key K, since the counter is derived from the current time
optional digits parameter can control the response length
optional window parameter controls the time window in seconds
returns the OATH integer code with {digits} length
"""
C = long(time.time() / window)
return HOTP(K, C, digits=digits)
By following the correct answer from #tadeck and #Anish-Shah, there is a simpler method to get the code without using struct and avoiding extra imports:
""" TOTP """
import hmac
import time
def totp(key: bytes):
""" Calculate TOTP using time and key """
now = int(time.time() // 30)
msg = now.to_bytes(8, "big")
digest = hmac.new(key, msg, "sha1").digest()
offset = digest[19] & 0xF
code = digest[offset : offset + 4]
code = int.from_bytes(code, "big") & 0x7FFFFFFF
code = code % 1000000
return "{:06d}".format(code)
This works with Python 3.
You can get the current TOTP code by calling totp(key) where the "key" is a bytes (commonly the base 32 decoded key).