I just try to use Django. when i try to create superuser with the createsuperuser and i try to use some common password like abcd1234 (because abc or 123 isn't allowed), it cannot accept it because apparently that my password is too common, i know that the createsuperuser use somekind of password list to match mine with theirs. I want to ask that whether it is possible to change the password list.
i already tried to open manage.py to find the createsuperuser method but i didnt find it because it only contains run(sys.argv)
You should be able to.
Look for a folder which follows the path:
\Python3\Lib\site-packages\django\contrib\auth or the equivalent on your system.
In it, you should see a file named common-passwords.txt.gz.
Inside it, there will be a file called common-passwords.new.txt
You should just be able to change the passwords on the list. One password per line. Passwords should be entirely lowercase as Django automatically translates passwords to lowercase for comparison against the common password list.
Relevant documentation: https://docs.djangoproject.com/en/2.2/topics/auth/passwords/#django.contrib.auth.password_validation.CommonPasswordValidator
Welcome to Stackoverflow!
You can follow the other answer as well. But you will have to place your password file whenever you change your virtualenv. Here is the way to keep it in the project.
Place your file in project folder where manage.py exists
Open settings.py from your projects folder and add the following
FILE_NAME = "custom_common_password_list.txt"
Create a file custom_common_password.py under projects folder
# projectname/custom_common_password.py
import os
from django.contrib.auth.password_validation import CommonPasswordValidator
from django.conf import settings
class CustomCommonPasswordValidator(CommonPasswordValidator):
def __init__(self):
super().__init__(password_list_path=os.path.join(settings.BASE_DIR, settings.FILE_NAME))
We are basically calling the CommonPasswordValidator with our file path.
Modify the AUTH_PASSWORD_VALIDATORS and add the following:
AUTH_PASSWORD_VALIDATORS = [
# ...
{
'NAME': 'projectname.custom_common_password.CustomCommonPasswordValidator',
},
#...
]
We comment the existing CommonPasswordValidator and place our custom validator. Make sure to replace projectname with your project name.
I would definitely recommend using a safer password.
Why? You don't want hackers to guess your password and hijack your website. Even small websites are targets of large fishing attempts and can be used to spread malware and do bad stuff.
One method that hackers use to gain entrance to your system is by using common password lists. So make sure that you choose a password that is not in such lists.
An easy to remember password which is still safe might consist of several words. As an alternative, you could use a password manager to remember a random string of characters for you.
You can find more suggestions here on how to create safe passwords: https://www.bu.edu/tech/support/information-security/security-for-everyone/how-to-choose-a-strong-password/
Related
I'm pretty new to Python and programming in general and am currently working on a little password manager. Thus far I have a script which can encode a txt file using the cryptography library. I am now wondering if it is possible to store information on a website or an account with a corresponding Password in the txt file or if I need to use something else than a txt file. What would you recommend?
The easiest way to do that is convert that dict to json and encrypt the string result.
It's easy convert to dict too. What I advise you to do if you're using this only for auth, is save like a key value store. Example:
{
"<user>": "<password>",
"<user2>" : "<password2>"
}
On this datastruct the code will be always O(1).
Yes, you can use a text file. That is not a problem. The text file will contain encrypted text.
Depending upon how secure and how many unique passwords, you probably want a salted encryption techique.
I would recommend passlib.
I will give as an example some code I recently made, and explain it (although I am not a cryptography expert):
from passlib.context import CryptContext
CRYPTO_CTX = CryptContext(schemes=["bcrypt"], deprecated="auto") # This means only use `'bcrypt'`.
#app.post("/login")
def login_user(user, db):
db_user = crud.get_user_by_username(db, username=user.username)
if db_user is None:
raise HTTPException(
status_code=400, detail=f"No username {user.username} found."
)
if not CRYPTO_CTX.verify(user.password, db_user.hashed_password): ## This is the essential portion
raise HTTPException(status_code=400, detail=f"Incorrect password.")
db_user = crud.update_user(db, db_user, {"last_visit": datetime.now(timezone.utc)})
return {"user": db_user}
This code is, as I said, for a website, and it is using FastAPI. I have removed some stuff for clarity while hopefully keeping enough context. Here is the breakdown:
You need to make a "Cryptographic context", which will know which hashing scheme(s) to use.
In my case, I am only using and allowing 'bcrypt', a best practice choice for 2020 (but you can choose others for flexibility).
I then create a '/login' web route, which is a URI endpoint that triggers a function.
That function receives user information from an HTTP POST that an end user submitted (and a database session).
The user is then searched on the database backend. Presuming she is found, the submitted password in the POST is compared to the password in the database, but that password is cryptographically protected.
Let's zoom in on that comparison:
if not CRYPTO_CTX.verify(user.password, db_user.hashed_password):
We are providing a plain text string (user.password) and a hashed string (db_user.hashed_password) to our CRYPTO_CTXs verify method. That is all that is needed, since the passlib library is doing all the heavy lifting.
How was the password encrypted? That was just as easy:
hashed_password = CRYPTO_CTX.hash(user.password)
And this does not just encrypt the password, it also salts it. In short, this means that if somehow the encryption were hacked, it would only work for that one entry. With salting, it's a two-step encryption process:
Create a password. Eg, 'Elderberries'
Add a salt to it: 'Elderberries34(*&#arst##!'
Hash that entire thing: 'B4B6603ABC670967E99C7E7F1389E40CD16E78AD38EB1468EC2AA1E62B8BED3A'
I'm new to LDAP. So I don't really know all my terms and fully understand all the terms yet. However, I'm working on an existing system and all the set up is done. I'm just adding a method to it.
I'm trying to write a method in Python using LDAP query. I've played around on LDAP Browser and can see that my query is correct. However, I'm not sure how to put it in a python method to return a list. The method needs to return a list of all the users' username. So far I have:
def getUsersInGroup(self, group):
searchQuery= //for privacy Im not going to share this
searchAttribute=["username"]
results = self.ldap.search_s(self.ldap_root, ldap.SCOP_SUBTREE,
searchQuery, searchAttribute)
I'm unsure how to go from here. I don't fully understand what the search_s method returns. I read online that its better to use search_s over search method because the while loop can be avoided. Could you please provide and example of where I can go from here. Thanks.
You need to perform a LDAP search something like:
# Find all Groups user is a member of:
import ldap
l = ldap.initialize("ldap://my_host")
l.simple_bind_s("[my_dn]", "[my_pass]")
myfilter = "(member=(CN=UserName,CN=Users,DC=EXAMPLE,DC=COM))"
# for all groups including Nested Groups (Only Microsoft Active Directory)
# (member:1.2.840.113556.1.4.1941:=CN=UserName,CN=Users,DC=EXAMPLE,DC=COM)
ldap_result = l.search("[BASE_DN]", ldap.SCOPE_SUBTREE, myfilter, None)
res_type, data = l.result(ldap_result, 0)
print(data)
You need to use the full dn of the user.
I have these lines (among other things) in my Django base settings file:
import os
STRIPE_PUBLIC_KEY = os.environ.get("STRIPE_PUBLIC_KEY", "your publishable test key")
STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "your secret test key")
I created those two environment variables in my virtualenv like this:
export STRIPE_SECRET_KEY="sk_test_example"
export STRIPE_PUBLIC_KEY="pk_test_example"
When I run env | grep STRIPE, I get this:
STRIPE_SECRET_KEY=sk_test_example
STRIPE_PUBLIC_KEY=pk_test_example
But for some reason, I keep getting this Stripe error: ""Invalid API Key provided: \"\u003C**** ****** **** key\u003E\". This key contains at least one space. Please delete the spaces and try again."
I tried exporting the environment variables again, once without quotation marks and once with single quotation marks, and I got the same result, so I tried printing the STRIPE_SECRET_KEY and STRIPE_PUBLIC_KEY from the settings file, and it returned the defaults, "your publishable test key" and "your secret test key". So that's why there were spaces. But why weren't the environment variables getting picked up?
So I tried getting rid of the defaults in my base settings so the variables look like this:
STRIPE_PUBLIC_KEY = os.environ.get("STRIPE_PUBLIC_KEY")
STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY")
That threw a NoneType error. I also tried the following:
STRIPE_PUBLIC_KEY = os.environ['STRIPE_PUBLIC_KEY']
STRIPE_SECRET_KEY = os.environ['STRIPE_SECRET_KEY']
That threw "KeyError: u'STRIPE_PUBLIC_KEY'". What do I need to change? I really don't want to hard-code these API keys.
It turns out that I'd forgotten (argh) to export the environment variables in my virtualenv postactivate file and was running the server in a different window, so once I put the Stripe API keys in the postactivate file, I needed to deactivate and activate the virtualenv before running the server.
For API keys, the quotes aren't necessary
export STRIPE_SECRET_KEY=sk_test_example
export STRIPE_PUBLIC_KEY=pk_test_example
It looks like the string format constructed with bash quotes is different than what Python is accepting. I don't know what formats these are, but this would definitely make sense.
Alternatively, you might want to look into a "dotenv" implementation such as django-dotenv.
This is a much more reliable way to work with strings like this. The problem is that when you're using different string formats (UTF-8 vs UTF-16 or Unicode), you may run into the situation where some program is expecting one format but receives another. The output you included is an example of what this looks like (hence my concern here).
Hope this helps!
I am new to Python, and I am trying to run a web.py app with Python Anywhere, but I keep getting the No template named index error. I've modified wsgi.py to use the following:
import web
import MySQLdb
urls = (
'/', 'index'
)
render = web.template.render('/home/user/templates/')
Any help would be greatly appreciated.
You've used the literal path '/home/user/templates/'. Unless your username is actually user, there is no such directory, and therefore attempting to read the index template out of that directory is going to fail.
If your username is, say, rhpt, you'd change that to '/home/rhpt/templates/'.
Even better, you might want to use os.path.expanduser('~/templates/') instead of hardcoding your username. (Then you can give your code to a friend, or a client, and they can host it without having to edit the code.)
I'm attempting to create directory trees in an gmail IMAP account. I've used the "create()" command in imaplib, but it seems to add the \\Noselect attribute to the created folder. This breaks gmail's nested labels feature - is there a way to remove the \\Noselect attribute, or avoid it being created in the first place?
Example:
>> imap.create("foo/bar")
('OK', [b'Success'])
>> imap.list()
[b'(\\Noselect \\HasChildren) "/" "foo"', b'(\\HasNoChildren) "/" "foo/bar"',...
I figured out a solution - Not sure if it's the 'best' way though. When creating a nested mailbox in one command, the top level mailboxes automatically are flagged \\Noselect. While it may be hacky, you can remove this flag by creating each level explicitly.
Example:
folder = "abc/def/ghi/jkl"
target = ""
for level in folder.split('/'):
target += "{}/".format(level)
imap.create(target)
I'll leave the question open to see if anyone has a better solution.
bjeanes: Sam's solution works for me as long as I leave off the trailing hierarchy delimiter.
So, if I want to create the nested folder a/b/c, I first create just plain "a". If I do an xlist, it has the hasNoChildren flag set. Now I create "a/b", and an xlist will now show "a" with the "hasChildren" flag set, and "a/b" with the "hasNoChildren" flag set. Finally, I create "a/b/c", and now "b" has the "hasChildren" flag set as well. A look at the gmail web interface confirms this as well.
Sam: thanks for figuring this out and posting the solution. "Hacky" beats "not working." :^)