How to generate a unique auth token in python? - python

I am trying to write a token based auth in flask for my android app. For that I need a unique token using which I can verify the user.
Itsdangerous library provide a JSONWebSignatureSerializer function using which I can create JWT token. So my first question is, is it safe to use JWT for mobile based auth ?
Secondly, I did a little bit research on how django rest framework generates its token.
def generate_key(self):
return binascii.hexlify(os.urandom(20)).decode()
Is this token unique or just a random one? Which one should I use for a mobile based auth?
What is the based way to generate a unique token for mobile application in python ?

You can use like as mentioned the builtin uuid module. The new secrets module released in 3.6 is also capable of creating unique tokens also.
from uuid import uuid4
rand_token = uuid4()
The function below creates a unique token every time it's called. The os.urandom method returns 20 random bytes as a string and the binascii.hexlify method converts each of those 20 bytes into 2-digit hex representation of that byte. This is why the return value is twice as long.
If you want to use this approach and need tokens to be specific length, use half of the length you need as an argument to the os.urandom method.
def generate_key(self):
return binascii.hexlify(os.urandom(20)).decode()

OK, this is old, but I'm chiming in anyway. You need to decide: Do you want unique or random? Choose one.
If you want unique, use UUID. The whole purpose of UUIDs is to make sure you generate something that's unique. UUID stands for Universally Unique ID.
If you want something that's random, use os.urandom. Truly random results cannot be limited to uniqueness constraints! That'd make them not random. Indeed, it'd make them UUIDs.
Now, for your question, you're asking for an auth token. That means you're using this for security purposes. UUIDs are the wrong solution and generating a secure number is the right one. Could you have a collision when generating a random number instead of a UUID? Yes. But it's unlikely unless you've got a gazillion users. You'll want to do your math on this, but my recommendation is: Don't use UUID when you mean to use random.
Oy.

Look at the uuid() library. Docs are here:
https://docs.python.org/2/library/uuid.html
and a previous discussion of the question is here:
How to create a GUID/UUID in Python
with lots of good details.

I wrote a little helper function for generating a unique token in django models. You can call it from the save() method of your model. It generates a candidate token using a defined function, searches the existing rows in the database for that candidate token. If it finds one, it trys again, otherwise, it returns the candidate string. Note that there is a small race condition in this, but is unlikely to occur with a token function with a sufficiently large range of outputs.
def generate_unique_token(Model,
token_field="token",
token_function=lambda: uuid.uuid4().hex[:8]):
"""
Generates random tokens until a unique one is found
:param Model: a Model class that should be searched
:param token_field: a string with the name of the token field to search in the model_class
:param token_function: a callable that returns a candidate value
:return: the unique candidate token
"""
unique_token_found = False
while not unique_token_found:
token = token_function()
# This weird looking construction is a way to pass a value to a field with a dynamic name
if Model.objects.filter(**{token_field:token}).count() is 0:
unique_token_found = True
return token
Then, you can find a unique token simply by calling
token = generate_unique_token(MyModelInstance, "token_field_name")
It even supports using other methods of generating tokens. For example, if you want to use the full uuid, you can simply call it like this:
token = generate_unique_token(MyModel, "token_field_name", lambda: uuid.uuid4().hex)

A possible solution is to AES encrypt the time when the token expires + the username which makes it fairly easy to spot expired tokens and requires no extra database space for the tokens

Related

Django/Python generate and unique Gift-card-code from UUID

I'm using Django and into a my model I'm using UUID v4 as primary key.
I'm using this UUID to generate a Qrcode used for a sort of giftcard.
Now the customer requests to have also a giftcard code using 10 characters to have a possibility to acquire the giftcard using the Qrcode (using the current version based on the UUID) as also the possibility to inter manually the giftcard code (to digit 10 just characters).
Now I need to found a way to generate this gift code. Obviously this code most be unique.
I found this article where the author suggest to use the auto-generaed id (integer id) into the generate code (for example at the end of a random string). I'm not sure for this because I have only 10 characters: for long id basically I will fire some of available characters just to concatenate this unique section.
For example, if my id is 609234 I will have {random-string with length 4} + 609234.
And also, I don't like this solution because I think it's not very sure, It's better to have a completely random code. There is a sort regular-format from malicious user point of view.
Do you know a way to generate an unique random string using, for example from an input unique key (in my case the UUIDv4)?
Otherwise, do you know some algorithm/approach to generate voucher codes?
import string
import secrets
unique_digits = string.digits
password = ''.join(secrets.choice(unique_digits) for i in range(6))
print(password)
The above code pallet generates a unique code of integers for the number of digits you want. In the above case, it will print a 6-digit unique Integer code.
If it doesn't let me know, what exactly you want.

How to make one function that takes two different values ​and generates a key in Python?

For example you have two mail accounts,I want give these two e-mail accounts to a function and receive a unique key word for these two emails.But there is a problem, when I change mail locations I have to get the same result again.
def two_mails(test#gmail.com, test2#gmail.com):
#algorithm codes
return "one_key"
Another time I have to use this function and generate this key.
if two_mails(test#gmail.com, test2#gmail.com) == "one_key":
#Other codes
Even if I change email locations, I need to get the same key
if two_mails(test2#gmail.com, test#gmail.com) == "one_key":
#Other codes
They should be able to create different keys with different mails.
def two_mails(different#gmail.com, different2#gmail.com):
#algorithm codes
return "different_key"
Please write the sample code while writing your idea.
EDITED#
I need to generate a key for these two mails and use it as id in db. I need to be able to do db query with this key when I need it. two_mails(different#gmail.com, different2#gmail.com).but sometimes mails change location two_mails(different2#gmail.com, different#gmail.com). What I need is to get the same result even if the mail locations change
You can create a function which takes the email address strings and sorts them and joins them as a single string and returns the hash.
So that if the positions are interchanged it gives the same output as after the sorting operation the order of the strings are maintained all the time:
import hashlib
def getUniquekey(*, first_email, second_email):
data = "".join(sorted([first_email, second_email]))
return hashlib.md5(data.encode('utf-8')).hexdigest()
print(getUniquekey(first_email="foo#yahoo.com", second_email="bar#yahoo.com"))
print(getUniquekey(first_email="bar#yahoo.com", second_email="foo#yahoo.com"))
Output:
c8cd4cdcd95e12c043fef21c0fb07a9f
c8cd4cdcd95e12c043fef21c0fb07a9f
If you sort your 2 email adresses before creating a key by internal hashing function of the 2-uple (email1,email2), the key will be consistant.
You have restricted your function to test#gmail.com, test2#gmail.com as arguments, if what you need is to parse different arguments to your function at every call, you'll need to include parameters:
def two_mails(first_email, second_email):
#make sure to replace test#gmail.com, test2#gmail.com with first_email, second_email throughout your functio
#algorithm codes
return "one_key"
and whenever you need to call the function, you can parse whatever appropriate arguments into it

Getting SalesforceMalformedRequest: Malformed request error

I am trying to execute this following code to push data to Salesforce using the simple_salesforce python library :
from simple_salesforce import Salesforce
staging_df = hive.execute("select * from hdmni")
staging_df = staging_df.toPandas()
# # staging_df['birth_date']= staging_df['birth_date'].dt.date
staging_df['birth_date'] = staging_df['birth_date'].astype(str)
staging_df['encounter_start_date'] = staging_df['encounter_start_date'].astype(str)
staging_df['encounter_end_date'] = staging_df['encounter_end_date'].astype(str)
bulk_data = []
for row in staging_df.itertuples():
d= row._asdict()
del d['Index']
bulk_data.append(d)
sf = Salesforce(password='', username='', security_token='')
sf.bulk.Delivery_Detail__c.insert(bulk_data)
I am getting this error while trying to send dictionary to salesforce :
SalesforceMalformedRequest: Malformed request
https://subhotutorial-dev-ed.my.salesforce.com/services/async/38.0/job/7500o00000HtWP6AAN/batch/7510o00000Q15TnAAJ/result.
Response content: {'exceptionCode': 'InvalidBatch',
'exceptionMessage': 'Records not processed'}
There's something about your query that is not correct. While I don't know your use case, by reading this line, you can tell that you are attempting to insert into a custom object/entity in Salesforce:
sf.bulk.Delivery_Detail__c.insert(bulk_data)
The reason you can tell is because of the __c suffix, which gets appended onto custom objects and fields (that's two underscores, by the way).
Since you're inserting into a custom object, your fields would have to be custom, too. And note, you've not appended that suffix onto them.
Note: Every custom object/entity in Salesforce does come with a few standard fields to support system features like record key (Id), record name (Name), audit fields (CreatedById, CreatedDate, etc.). These wouldn't have a suffix. But none of the fields you reference are any of these standard system fields...so the __c suffix would be expected.
I suspect that what Salesforce is expecting in your insert operation are field names like this:
Birth_Date__c
Encounter_Start_Date__c
Encounter_End_Date__c
These are referred to as the API name for both objects and fields, and anytime code interacts with them (whether via integration, or on code that executes directly on the Salesforce platform) you need to make certain you're using this API name.
Incidentally, you can retrieve this API name through a number of ways. Probably easiest is to log into your Salesforce org, and in Setup > Object Manager > [some object] > Fields and Relationships you can view details of each field, including the API name. Here's a screen shot.
You can also use SObject describe APIs, either in native Apex code, or via integration and either the REST or SOAP APIs. Here's part of the response from the describe API request to the describe REST endpoint for the same object as my UI example above, found here at https://[domain]/services/data/v47.0/sobjects/Expense__c/describe:
Looking at the docs for the simple-salesforce python library you're using, they've surfaced the describe API. You can find some info under Other Options. You would invoke it as sf.SObject.describe where "SObject" is the actual object you want to find the information about. For instance, in your case you would use:
sf.Delivery_Detail__c.describe()
As a good first troubleshooting step when interacting with a Salesforce object, I'd always recommend double-checking correctly referencing an API name. I can't tell you how many times I've bumped into little things like adding or missing an underscore. Especially with the __c suffix.

'if' element is not in list on Google App Engine

I am building an application for Facebook using Google App Engine. I was trying to compare friends in my user's Facebook account to those already in my application, so I could add them to the database if they are friends in Facebook but not in my application, or not if they are already friends in both. I was trying something like this:
request = graph.request("/me/friends")
user = User.get_by_key_name(self.session.id)
list = []
for x in user.friends:
list.append(x.user)
for friend in request["data"]:
if User.get_by_key_name(friend["id"]):
friendt = User.get_by_key_name(friend["id"])
if friendt.key not in user.friends:
newfriend = Friend(friend = user,
user = friendt,
id = friendt.id)
newfriend.put()
graph.request returns an object with the user's friends. How do I compare content in te two lists of retrieved objects. It doesn't necessarily need to be Facebook related.
(I know this question may be quite silly, but it is really being a pain for me.)
If you upgrade to NDB, the "in" operator will actually work; NDB implements a proper eq operator on Model instances. Note that the key is also compared, so entities that have the same property values but different keys are considered unequal. If you want to ignore the key, consider comparing e1._to_dict() == e2._to_dict().
You should write a custom function to compare your objects, and consider it as a comparison of nested dictionaries. As you will be comparing only the attributes and not functions, you have to do a nested dict comparison.
Reason: All the attributes will be not callable and hopefully, might not start with _, so you have to just compare the remaining elements from the obj.dict and the approach should be bottom up i.e. finish off the nested level objects first (e.g. the main object could host other objects, which will have their own dict)
Lastly, you can consider the accepted answer code here: How to compare two lists of dicts in Python?

Best practice for two way hashing in python?

I want to allow users to validate their email address by clicking on a link. The link would look something like
http://www.example.com/verifyemail?id=some-random-string
When I am sending this email, I want to be able to easily generate this 'some-random-string' from row id of user, an integer. and when user clicks on this link, generate that integer back.
Only requirement is this 'some-random-string' should be as opaque and non-guessable to the user as possible.
Finally, this is what I settled on
def p3_encrypt_safe(plain, key):
return base64.urlsafe_b64encode(p3_encrypt(plain, key))
used the nice crypto library from http://www.nightsong.com/phr/crypto/p3.py
addition of base64 safe encoding is mine.
Use encryption, that's exactly what it's designed for. Blowfish, AES, even DES3 if you don't need particularly high security.
Alternatively, you could compute an SHA-256 or SHA-512 (or whatever) hash of the email address and store it in a database along with the email address itself. That way you can just look up the email address using the hash as a key.
Your best choice is to generate a hash (one-way function) of some of the user's data. For example, to generate a hash of user's row id, you could use something like:
>>> import hashlib
>>> hashlib.sha1('3').hexdigest()
'77de68daecd823babbb58edb1c8e14d7106e83bb'
However, basing your pseudorandom string only on a row id is not very secure, as the user could easily reverse the hash (try googling 77de68daecd823babbb58edb1c8e14d7106e83bb) of such a short string.
A simple solution here is to "salt" the hashed string, i.e. add the same secret string to every value that is hashed. For example:
>>> hashlib.sha1('3' + 'email#of.user' + 'somestringconstant').hexdigest()
'b3ca694a9987f39783a324f00cfe8279601decd3'
If you google b3ca694a9987f39783a324f00cfe8279601decd3, probably the only result will be a link to this answer :-), which is not a proof, but a good hint that this hash is quite unique.

Categories