mongoDB: python code issue - python

could it be the wrong bottle version?
I lookeed in the sessionDAO file provided by the admins, and they do it the same as i do it;
the code:
def __init__(self, db):
self.db = db
self.users = self.db.users
self.SECRET = 'verysecret'
says:
[1] connect to the blog db
[2] select the users collection
and in the login code i have:
def validate_login(self, username, password):
user = None
try:
# XXX HW 2.3 Students Work Here
# you will need to retrieve right document from the users collection.
password = self.make_pw_hash(password)
user = self.users.find({"_id":username,"password":password})
I know self, username and password; it should be a simple find by document, as i wrote it; I now see that there might be a indentation problem, wich i can see it only on stackoverflow, in notepad++ it's not there;
and:
def add_user(self, username, password, email):
password_hash = self.make_pw_hash(password)
user = {'_id': username, 'password': password_hash}
if email != "":
user['email'] = email
try:
# XXX HW 2.3 Students work here
# You need to insert the user into the users collection.
# Don't over think this one, it's a straight forward insert.
self.users.insert(user)
I know self, username, password and email;
The document is prepared by default: user = {'_id': username, 'password': password_hash}
It should be a simple insert: self.users.insert(user)

Whenever you make any change to the source code, you need to restart the server for those changes to take effect.

Change the line
user = self.users.find({"_id":username,"password":password})
to
user = self.users.find_one({"_id":username})

Related

Changing user's password using Flask and SQLite

I am trying to implement a function to change the user's password. I am storing only the hash in DB not the password and I want to ask the user to enter the old password first then the new one. I want to check if the old password's hash is matching the one stored in DB and if so, to update it with the new one. I am doing something wrong as the code is not passing the validation checks and I am having an error: "Invalid password".
Any help, would be appreciated.
#app.route("/change_password", methods=["GET", "POST"])
#login_required
def change_password():
user_id=session["user_id"]
if request.method=="POST":
password = request.form.get("password")
hash = generate_password_hash(password)
new_password = request.form.get("new_password")
confirm_new_password = request.form.get("confirm_new_password")
new_hash = generate_password_hash(new_password)
#Validations:
if not password:
return apology("must provide password", 400)
if not new_password:
return apology("must provide a new password", 400)
#Ensure password confirmation is provided
if not confirm_new_password:
return apology("must confirm new password", 400)
#Check if new password matches
if new_password!= confirm_new_password:
return apology("password does not match", 400)
# Query database for the current password
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
# Ensure username exists and password is correct
if len(rows) != 1:
return apology("invalid password", 400)
#Update DB with the new_hash
else:
db.execute ("UPDATE users SET hash=:new_hash WHERE id=:id", new_hash = new_hash, id = user_id)
return redirect("/")
else:
return render_template("change_password.html")
There are quite some problems with your code...
The biggest problem
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
You have to search for the user name, not for the hash!!! Imagine, two users have the same password, or a user enters the wrong password, but that is the password of another user...
I never used direct access to sqlite, only via sqlalchemy, but from a quick look at the docs ( https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executemany ) db.execute does not return e.g. rows, but you need to query it.
e.g. after your db.execute you need to do a db.fetchone or db.fetchall, see above linked documentation.
Also, the order of your code could be improved.
e.g. first, you generate the hash of a new password, and then afterwards you check whether there is a password at all - this should be switched.
Speaking of validation, much of it could be done via e.g. flask-wtforms, so you don't need so much validation code on your own.

Best way to create user accounts from a file in Python?

I am trying to have the ability to mass create user accounts from a file that I upload in Python. So instead of creating users one at a time I can be giving a list of X amount of users and quickly create them. So for instance if I have a file(newusers.csv) that contains the usernames below how would I go about easily doing this?
First name, Last name, Username.
tom cat tcat11
Jerry Mouse Jmouse21
Mini Mouse Mmouse
Below is the code I have which is supposed to create the users:
def user_account():
userInformation = readFile("newusers.csv")
try:
subprocess.run(['useradd','-p', userInformation[1:]])
except:
print(f"failed to add user.")
sys.exit(1)
I don't know what specific options etc. you want in your useradd command so that i'm leaving out of this. However regarding the approach: This is one way you could approach it by creating a User class.
import csv
class User:
def __init__(self, firstname, lastname, username):
self.firstname = firstname
self.lastname = lastname
self.username = username
def save(self):
try:
# WHATEVER COMMAND AND OPTIONS YOU ARE LOOKING TO RUN
# USING self.username, ETC. AS ARGS
except:
print("failed to add user")
sys.exit(1) # if you don't want to attempt any of the other users
#staticmethod
def mass_save(users):
for user in users:
user.save()
#staticmethod
def read_users_from_file(file_path):
with open(file_path, "rt") as f:
users = csv.reader(f)
next(users) # Skip header row
return [User(*row) for row in users] # Unpack each userinfo row from csv upon instantiation
if __name__ == "__main__":
users = User.read_users_from_file("users.csv")
User.mass_save(users)

Accessing specific item in sqlite3 database when user and password matches

I've created a login GUI with sqlite in python and i've got it working correctly, however I want it to do something else as well when it logs in.
My sqlite database currently has the following columns;
Username, Email, Password, Workstation, Directory
I've found that you can take an item string in the table by using something like;
connection.fetchall()[index]
However, I don't know how to implement it into my code to check for the user that logged in.
username = "username"
password = "password"
# database information
connection = sqlite3.connect(databasepath+'\login.db')
result = connection.execute("SELECT * FROM USERS WHERE USERNAME = ? AND PASSWORD = ?", (username, password))
if (len(result.fetchall()) > 0):
#some code#
I want to access the 'Directory' item for the user that logged in

Is it possible to deny access to copied password field in database?

My Django app password in database looks like this:
pbkdf2_sha256$100000$XXXXXXXXXX$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
But if I duplicate it to another user, I could log in to that user's account.
Assuming a database breach or some kind of injection, can I detect if password was somehow duplicated/copied so that I can deny access to the account or alert admins?
as Selcuk says if some one has access to write into your database, he/she can do anything like generate password as your system want.
but you can make it harder to change password.
if you want to deny password copy from database you must create your own user model and update hashing algorithm like this.
first create a user model:
from django.contrib.auth.hashers import make_password, check_password
class MyUser(User):
def set_password(self, raw_password):
self.password = make_password(self.username + raw_password)
self._password = raw_password
def check_password(raw_password):
def setter(raw_password):
self.set_password(raw_password)
self._password = None
self.save(update_fields=['password'])
return check_password(self.username + raw_password, self.password. setter)
by these changes user password hashes are contain username and copy hash for other user does not works correctly

Django Python Social Auth only allow certain users to sign in

I want only users from a #companyname.net email or from a list of email addresses to be able to sign in with Python Social Auth through google+. How would I accomplish this?
SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ['companyname.net']
is what I currently have in settings.py, but that only allows #companyname.net-ers to sign in.
One way to solve this is overriding python-social-auth pipeline.
You can override create_user with something like:
def create_user(strategy, details, user=None, *args, **kwargs):
if user:
return {'is_new': False}
allowed_emails = get_list_of_emails()
fields = dict((name, kwargs.get(name, details.get(name)))
for name in strategy.setting('USER_FIELDS', USER_FIELDS))
if not fields:
return
if fields[email] in allowed_emails:
return {
'is_new': True,
'user': strategy.create_user(**fields)
}
return
This method get_list_of_emails() is to be used as a way to load the emails from file ou from database. It needs to return a list of emails.
Then, in the SOCIAL_AUTH_PIPELINE in your settings you replace the create_user to your custom method:
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'path.to.my.method.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
)
This way you can keep the domais whitelist, and then store the emails you want somewhere where you can load them with the method get_list_of_emails()
more on the docs
Limiting the registration to some emails OR domains is called whitelisting.
As the documentation explains, you have two possible ways of whitelisting, namely by supplying a
list of domains to be whitelisted, SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_DOMAINS = ['foo.com', 'bar.com']
list of email addresses to be whitelisted, SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_EMAILS = ['me#foo.com', 'you#bar.com']
Since OP wants
to allow everyone for #companyname.net and only some specific others from other domains.
then OP can keep using SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_DOMAINS as OP is already doing and also introduce SOCIAL_AUTH_<BACKEND_NAME>_WHITELISTED_EMAILS to add the specific emails OP wants also to login.
Here is my tested implementation:
import os
import psycopg2
from Utils.common import setup_logging
LOG = setup_logging(__name__)
USER_FIELDS = ['username', 'email']
def get_whitelisted_emails():
whitelisted_domains_emails = []
try:
connection = psycopg2.connect(user=os.environ.get('DB_USER'),
password=os.environ.get('DB_PASSWORD'),
host='localhost',
port=os.environ.get('DB_PORT'),
database=os.environ.get('DB_NAME'))
cursor = connection.cursor()
get_whitelisted_domains_emails = "SELECT domain, email FROM cortex_emails WHERE is_active=True;"
cursor.execute(get_whitelisted_domains_emails)
whitelisted_domains_emails = cursor.fetchall()
connection.close()
except(Exception, psycopg2.Error) as error:
LOG.info('Failed to connect to database...')
return [email for _, email in whitelisted_domains_emails]
def create_user(strategy, details, user=None, *args, **kwargs):
if user:
return {'is_new': False}
allowed_emails = get_whitelisted_emails()
fields = dict((name, kwargs.get(name, details.get(name)))
for name in strategy.setting('USER_FIELDS', USER_FIELDS))
if not fields:
return
if fields['email'] in allowed_emails:
return {
'is_new': True,
'user': strategy.create_user(**fields)
}
return

Categories

Resources