I am new to Flask learning it from a tutorial video. I am trying to authenticate and get a access token. I have created user class which is in user.py :
class User:
def __init__(self, _id, username, password):
self.id = _id,
self.username = username,
self.password = password
in my security.py :
from werkzeug.security import safe_str_cmp
from user import User
users = [
User(1, 'user1', 'abcxyz'),
]
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, password):
user = username_table.get(username, None)
print(username) # user1
print(password) # abcxyz
print(username_table) #{('user1',): <user.User object at 0x000001AD37543358>}
print(user) # None
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
return user
def identity(payload):
user_id = payload['identity']
return userid_table.get(user_id, None)
As you can see I was trying to debug with printing out everything. Inside authentication function I got username and password successfully from the request. But In result the user variable is None. Looks like .get method is not working and that is causing the error but I can not figure out why am I getting None there. I have showed the outputs in front of print functions
I think you have a typo in your program. Please remove the , after the username in __init__ of the User class. That is syntactically correct and way of creating a tuple with a single element which is not what you need.
>>> tuple_with_single_element = "python",
>>> tuple_with_single_element
... ('python',)
>>> python_string = "python"
>>> python_string
... 'python'
Related
I am trying to restrict logged user to access URL routes that are not assigned to them. As soon a user had logged, for example user1, will be redirected to https://myurl.com/user1. So far, that works good, but I would like to avoid that user1 can see the content in the route of user2 in https://myurl.com/user2.
Below you can see the code I am currently using.
import tornado
from tornado.web import RequestHandler
import sqlite3
# could define get_user_async instead
def get_user(request_handler):
return request_handler.get_cookie("user")
# could also define get_login_url function (but must give up LoginHandler)
login_url = "/login"
db_file = "user_login.db"
connection = None
cursor = None
# optional login page for login_url
class LoginHandler(RequestHandler):
def get(self):
try:
errormessage = self.get_argument("error")
except Exception:
errormessage = ""
self.render("login.html", errormessage=errormessage)
def check_permission(self, username, password):
connection = sqlite3.connect(db_file)
cursor = connection.cursor()
cursor.execute("SELECT * FROM users WHERE username=? AND password=?", (username, password))
data = cursor.fetchone()
if username == data[1] and password == data[2]:
return True
return False
def post(self):
username = self.get_argument("username", "")
password = self.get_argument("password", "")
auth = self.check_permission(username, password)
if auth:
self.set_current_user(username)
self.redirect(self.get_argument("next", f"/{username}"))
else:
error_msg = "?error=" + tornado.escape.url_escape(
"Login failed, please try again or contact your system administrator."
)
self.redirect(login_url + error_msg)
def set_current_user(self, user):
if user:
self.set_cookie("user", tornado.escape.json_encode(user))
else:
self.clear_cookie("user")
# optional logout_url, available as curdoc().session_context.logout_url
# logout_url = "/logout"
# optional logout handler for logout_url
class LogoutHandler(RequestHandler):
def get(self):
self.clear_cookie("user")
self.redirect(self.get_argument("next", "/"))
I am learning simple python JWT module. I am creating a token using restfull api and then using the same token to get the data, But unfortunately i am getting an error "User does not exist".
Python Code snippet
class User:
def __init__(self, _id, username, password):
self.id = _id
self.username = username
self.password = password
users = [
User(1, "bob", "asdf")
]
username_mapping = {u.username: u for u in users}
userid_mapping = {u.id: u for u in users}
def authenticate(username, password):
user = username_mapping.get(username, None)
if user and user.password == password:
return user
def identity(payload):
user_id = payload["identity"]
return username_mapping.get(user_id, None)
##Using this function for authentication
app = Flask(__name__)
app.secret_key = "jose"
api = Api(app)
jwt = JWT(app,authenticate, identity)
def abort_if_item_not_exist(name):
item = next(filter(lambda x: x["name"] == name, items), None)
if item == None:
abort(404, message = "This item does not exist")
else:
return {"item": item}
class Item(Resource):
#jwt_required()
def get(self,name):
return abort_if_item_not_exist(name)
I have found the answer, thanks to jsp, he pointed a website. I analyzed and got the payload identity id. Then I realized I am getting an ID and I am comparing it with wrong value. it is my typo only.
def identity(payload):
user_id = payload["identity"]
return userid_mapping.get(user_id, None) # This needs to be changed
I am using passlib to store the password in my sqlite database. I am not getting error while storing the new password(registration). But when I try to login with the same user I am getting this error 'TypeError: hash must be unicode or bytes, not sqlalchemy.orm.attributes.InstrumentedAttribute'.
My script
**models.py**
class Login(db.Model,UserMixin):
"Creates username and password"
id = db.Column(db.Integer,primary_key=True,nullable=False)
username = db.Column(db.String,nullable=False)
password = db.Column(db.String,nullable=False)
email = db.Column(db.String,nullable=False)
def __repr__(self):
return f"Login('{self.id}','{self.username}','{self.password}','{self.email}')"
**routes.py**
from myfolder.security import encrypt_password,check_encrypted_password
def login():
if request.method == 'POST':
username = request.form.get('username')
password1 = request.form.get('password')
data = {'username':username}
#fetch the email id of the user whose logged in
user_email_id = Login.query.filter(Login.username==username).values(Login.email,Login.password)
for logged_user in user_email_id:
logged_email_id = logged_user.email
hashed = logged_user.password
session['logged_user'] = logged_email_id
completion = validate(username)
if completion ==False:
error = 'error.'
else:
password_check = check_encrypted_password(password1,Login.password)
if password_check ==False:
error = 'error.'
else:
user = Login()
user.name=username
user.password=password
login_user(user)
error = 'Success'
api_response = {'data':data,'error':error}
return jsonify(api_response)
I have created new file called security.py
from passlib.context import CryptContext
pwd_context = CryptContext(
schemes=["pbkdf2_sha256"],
default="pbkdf2_sha256",
pbkdf2_sha256__default_rounds=30000
)
def encrypt_password(password):
return pwd_context.encrypt(password)
def check_encrypted_password(password, hashed):
return pwd_context.verify(password, hashed)
In the login method I tried different ways but nothing is working.I tried passing the password here.
password_check = check_encrypted_password(password1,password)
But I am getting this error
raise ValueError("hash could not be identified")
ValueError: hash could not be identified
How should I verify my password and login?
There is a bug in your code. The line
password_check = check_encrypted_password(password1,Login.password)
should be
password_check = check_encrypted_password(password1,hashed)
Instead of passing in the hashed password from the database, you are currently passing in the sqlalchemy column definition for the password.
There are number of other errors in you code that you should be aware of.
Most of the time you use "password1", but there is also one instance of "password".
If a username is provided that is not in the database, both "logged_email_id" and "hashed" variables would not be defined.
So I would suggest to refactor you code to this:
from myfolder.security import encrypt_password,check_encrypted_password
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
data = {'username':username}
#fetch the email id of the user whose logged in
logged_user = Login.query.filter(Login.username==username).values(Login.email,Login.password).one_or_none()
if not logged_user:
error = 'error.'
else:
session['logged_user'] = logged_user.email
completion = validate(username)
if completion ==False:
error = 'error.'
else:
password_check = check_encrypted_password(password,logged_user.password)
if password_check ==False:
error = 'error.'
else:
user = Login()
user.name=username
user.password=password
login_user(user)
error = 'Success'
api_response = {'data':data,'error':error}
return jsonify(api_response)
In this code I have:
Replaced "password1" with "password", to ensure that "user.password=password" does not generated an error because password is not defined.
Replaced the for loop with "one_or_none()". This returns the first value or none, if the username cannot be found.
Check that the value returned from the database query exists, before trying to user the result of the query.
In a login authentication module for a webapp, I'm trying to compare two values; a user entered password, and a password hash that is stored in a sqlite3 database (the hash just being the string 'password' for now).
The code is as follows:
#app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
if request.form['login'] == 'Login':
username = request.form['username']
user_password = request.form['password']
#print query_db("SELECT * FROM Users WHERE Username=?", username, one=True)[0]
try:
user = User(query_db("SELECT * FROM Users WHERE Username=?", username, one=True)[0])
print user.hash
except IndexError:
return "INVALID USERNAME!"
hash = User.hash
print hash
#print whatisthis(hash)
print user_password
#print whatisthis(user_password)
if user_password == hash:
print "wooo!"
#login_user(user)
#flash("Logged in successfully.")
return "LOGIN SUCCESS!"
#return redirect(request.args.get("next") or url_for("index"))
else:
return "INVALID PASSWORD!"
return render_template("login.html")
User is a class that gets its attributes (like .hash) from the database after accessing the database through the ID. The print statements are simply for debugging, and they do show correctly the two strings (hash or User.hash, and user_password) to be identical when printing them to the terminal. However, they do not evaluate True in the if user_password == hash statement for some reason, always defaulting to the else case. Additionally, if I try to perform .encode('base64') on both strings, user_password properly changes to base64, however hash or User.hash stays the same even after the .encode!
Thanks a lot for your help with this odd problem!
User hash = user.hash rather than hash = User.hash.
>>> class User:
... hash = ""
... def __init__(self, hash):
... self.hash = hash
...
>>> u1 = User("hash1")
>>> User.hash
''
>>> u1.hash
'hash1'
If you didn't set User.hash somewhere else in your code, User.hash will still has default value which is ''. Therefore, since your User.hash is "password", it is very likely to be set by other code.
In my function I read user's data from session and store them in a dictionary. Next I'm sending it to 'register' function from registration.backend but the function somehow get's it empty and a KeyError is thrown. Where are my data gone ? The code from function calling 'register' function :
data = request.session['temp_data']
email = data['email']
logging.debug(email)
password1 = data['password1']
userdata = {'email': email, 'password1': password1}
logging.debug(userdata)
backend = request.session['backend']
logging.debug(backend)
user = backend.register(userdata)
And the register function (whole source here : http://bitbucket.org/ubernostrum/django-registration/src/tip/registration/backends/default/init.py ) :
class DefaultBackend(object):
def register(self, request, **kwargs):
logging.debug("backend.register")
logging.debug(kwargs)
username, email, password = kwargs['email'], kwargs['email'], kwargs['password1']
Debug after invoking them :
2010-07-09 19:24:35,020 DEBUG my#email.com
2010-07-09 19:24:35,020 DEBUG {'password1': u'a', 'email': u'my#email.com'}
2010-07-09 19:24:35,020 DEBUG <registration.backends.default.DefaultBackend object at 0x15c6090>
2010-07-09 19:24:35,021 DEBUG backend.register
2010-07-09 19:24:35,021 DEBUG {}
Why the data could be missing ? Am I doing something wrong ?
#edit for Silent-Ghost
register() takes exactly 2 arguments (3 given)
112. backend = request.session['backend']
113. logging.debug(backend)
114. user = backend.register(request, userdata)
No need to mess with ** in register method. What you want to do is simply pass dictionary to register method:
user = backend.register( request, userdata ) # you need to pass request as definition says
def register( self, request, userdata ): # note lack of **
logging.debug("backend.register")
logging.debug( userdata ) # should work as expected
username, email, password = userdata['email'], userdata['email'], userdata['password1']
Judging by the method's signature:
you need to unpack your dictionary
you need to pass relevant request variable
Something like this:
backend.register(request, **userdata)
Assuming register is a method on backend instance.
this perfectly work
class Logging():
def debug(self,f):
print f
class DefaultBackend(object):
def register(self, request, **kwargs):
logging.debug("backend.register")
logging.debug(kwargs)
username, email, password = kwargs['email'], kwargs['email'], kwargs['password1']
class Request:
def __init__(self):
self.session = {}
request = Request()
logging=Logging()
request.session['temp_data']={'password1': u'a', 'email': u'my#email.com'}
request.session['backend']=DefaultBackend()
data = request.session['temp_data']
email = data['email']
logging.debug(email)
password1 = data['password1']
userdata = {'email': email, 'password1': password1}
logging.debug(userdata)
backend = request.session['backend']
logging.debug(backend)
user = backend.register(request,**userdata)