Issue #316: TypeError("Unicode-objects must be encoded before hashing")
Reported by: | Wise Kaa |
State: | closed |
Created on: | 2018-05-07 15:41 |
Updated on: | 2020-06-18 20:23 |
Description
What is it ?
2018-05-07 18:34:08.877 INFO [kallithea.lib.base] IP: 46.18.200.242 User: <AuthUser('id:1[default] auth:True')> accessed /_admin/register Error - <type 'exceptions.TypeError'>: Unicode-objects must be encoded before hashing URL: http://git.kngk.org/_admin/register File '/usr/local/lib/python2.7/site-packages/weberror/errormiddleware.py', line 171 in __call__ app_iter = self.application(environ, sr_checker) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/middleware/sessionmiddleware.py', line 62 in __call__ return self.wrap_app(environ, session_start_response) File '/usr/local/lib/python2.7/site-packages/routes/middleware.py', line 131 in __call__ response = self.app(environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 103 in __call__ response = self.dispatch(controller, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 313 in dispatch return controller(environ, start_response) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/base.py', line 446 in __call__ return WSGIController.__call__(self, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 214 in __call__ response = self._dispatch_call() File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 164 in _dispatch_call response = self._inspect_call(func) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 107 in _inspect_call result = self._perform_call(func, args) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 57 in _perform_call return func(**args) File '<decorator-gen-2>', line 2 in register File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 857 in __wrapper return func(*fargs, **fkwargs) File '/usr/local/lib/python2.7/site-packages/kallithea/controllers/login.py', line 151 in register UserModel().create_registration(form_result) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 186 in create_registration new_user = self.create(form_data) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 92 in create v = get_crypt_password(v) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 136 in get_crypt_password return KallitheaCrypto.hash_string(password) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 110 in hash_string return bcrypt.hashpw(str_, bcrypt.gensalt(10)) File '/usr/local/lib/python2.7/site-packages/bcrypt/__init__.py', line 62 in hashpw raise TypeError("Unicode-objects must be encoded before hashing") TypeError: Unicode-objects must be encoded before hashing
Kallithea 0.3.4
Attachments
Comments
Comment by Wise Kaa, on 2018-05-07 15:42
Comment by Wise Kaa, on 2018-05-07 15:43
Comment by Wise Kaa, on 2018-05-07 15:45
Comment by Mads Kiilerich, on 2018-05-07 15:57
That sounds like https://kallithea-scm.org/repos/kallithea/changeset/fefd7279e798e279ed71acf3d538319412d2fb44?at=stable in 0.3.4 doesn't work.
Can you reproduce the problem? Which unicode username/password?
Comment by Wise Kaa, on 2018-05-07 16:21
Yes. It is on register page. I don't Unicode strings, just ascii string. Username: stas Password: QazWsx321
Comment by Thomas De Schampheleire, on 2018-05-07 19:35
Can you try following patch?
diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py --- a/kallithea/lib/auth.py +++ b/kallithea/lib/auth.py @@ -103,6 +103,12 @@ class KallitheaCrypto(object): :param password: password to hash """ + try: + password = str(password) + except UnicodeEncodeError: + log.warning('rejecting non-ascii password') + return False + log.info(">>>>>>>>>>>>>>>>>> hash_string(%s)", repr(str_)) if is_windows: return hashlib.sha256(str_).hexdigest() elif is_unix: @@ -127,6 +133,7 @@ class KallitheaCrypto(object): except UnicodeEncodeError: log.warning('rejecting non-ascii password') return False + log.info(">>>>>>>>>>>>>>>>>> hash_check(%s)", repr(password)) if is_windows: return hashlib.sha256(password).hexdigest() == hashed elif is_unix: @@ -138,6 +145,7 @@ class KallitheaCrypto(object): def get_crypt_password(password): + log.info(">>>>>>>>>>>>>>>>>> get_crypt_password(%s)", repr(password)) return KallitheaCrypto.hash_string(password)
It seems that the method used for calculating the password hash on registration is different than the one fixed in the commit Mads referenced, used to verify a password on login.
A simple test with the credentials you mentioned: 'stas' / 'QazWsx321' does not cause this problem on my side, though.
Please send the output of the extra '>>>>>>>>' log statements from your test. We should be able to see exactly what Kallithea sees as password.
What version of bcrypt is in use? (Use 'pip freeze | grep bcrypt'). On my side, I have py-bcrypt 0.3, but I tested with 0.4 as well.
How did you install Kallithea?
Comment by Wise Kaa, on 2018-05-08 05:56
Bcrypt: bcrypt==3.1.4 py-bcrypt==0.4
My machine is FreeBSD 10.4-STABLE.
2018-05-08 08:54:49.112 INFO [kallithea.lib.base] IP: 46.18.200.242 User: <AuthUser('id:1[default] auth:True')> accessed /_admin/register 2018-05-08 08:54:49.205 INFO [kallithea.lib.auth] >>>>>>>>>>>>>>>>>> get_crypt_password(u'QweAsd321') Error - <type 'exceptions.UnboundLocalError'>: local variable 'password' referenced before assignment URL: http://git.kngk.org/_admin/register File '/usr/local/lib/python2.7/site-packages/weberror/errormiddleware.py', line 171 in __call__ app_iter = self.application(environ, sr_checker) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/middleware/sessionmiddleware.py', line 62 in __call__ return self.wrap_app(environ, session_start_response) File '/usr/local/lib/python2.7/site-packages/routes/middleware.py', line 131 in __call__ response = self.app(environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 103 in __call__ response = self.dispatch(controller, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 313 in dispatch return controller(environ, start_response) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/base.py', line 446 in __call__ return WSGIController.__call__(self, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 214 in __call__ response = self._dispatch_call() File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 164 in _dispatch_call response = self._inspect_call(func) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 107 in _inspect_call result = self._perform_call(func, args) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 57 in _perform_call return func(**args) File '<decorator-gen-2>', line 2 in register File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 864 in __wrapper return func(*fargs, **fkwargs) File '/usr/local/lib/python2.7/site-packages/kallithea/controllers/login.py', line 151 in register UserModel().create_registration(form_result) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 186 in create_registration new_user = self.create(form_data) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 92 in create v = get_crypt_password(v) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 143 in get_crypt_password return KallitheaCrypto.hash_string(password) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 107 in hash_string password = str(password) UnboundLocalError: local variable 'password' referenced before assignment
Comment by Wise Kaa, on 2018-05-08 06:04
I changed password
to str_
2018-05-08 09:03:16.038 INFO [kallithea.lib.base] IP: 46.18.200.242 User: <AuthUser('id:1[default] auth:True')> accessed /_admin/register 2018-05-08 09:03:16.141 INFO [kallithea.lib.auth] >>>>>>>>>>>>>>>>>> get_crypt_password(u'QweAsd321') 2018-05-08 09:03:16.141 INFO [kallithea.lib.auth] >>>>>>>>>>>>>>>>>> hash_string(u'QweAsd321') Error - <type 'exceptions.TypeError'>: Unicode-objects must be encoded before hashing URL: http://git.kngk.org/_admin/register File '/usr/local/lib/python2.7/site-packages/weberror/errormiddleware.py', line 171 in __call__ app_iter = self.application(environ, sr_checker) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/middleware/sessionmiddleware.py', line 62 in __call__ return self.wrap_app(environ, session_start_response) File '/usr/local/lib/python2.7/site-packages/routes/middleware.py', line 131 in __call__ response = self.app(environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 103 in __call__ response = self.dispatch(controller, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 313 in dispatch return controller(environ, start_response) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/base.py', line 446 in __call__ return WSGIController.__call__(self, environ, start_response) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 214 in __call__ response = self._dispatch_call() File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 164 in _dispatch_call response = self._inspect_call(func) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 107 in _inspect_call result = self._perform_call(func, args) File '/usr/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 57 in _perform_call return func(**args) File '<decorator-gen-2>', line 2 in register File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 864 in __wrapper return func(*fargs, **fkwargs) File '/usr/local/lib/python2.7/site-packages/kallithea/controllers/login.py', line 151 in register UserModel().create_registration(form_result) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 186 in create_registration new_user = self.create(form_data) File '/usr/local/lib/python2.7/site-packages/kallithea/model/user.py', line 92 in create v = get_crypt_password(v) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 143 in get_crypt_password return KallitheaCrypto.hash_string(password) File '/usr/local/lib/python2.7/site-packages/kallithea/lib/auth.py', line 116 in hash_string return bcrypt.hashpw(str_, bcrypt.gensalt(10)) File '/usr/local/lib/python2.7/site-packages/bcrypt/__init__.py', line 62 in hashpw raise TypeError("Unicode-objects must be encoded before hashing") TypeError: Unicode-objects must be encoded before hashing
Comment by Wise Kaa, on 2018-05-08 08:13
I was correct method:
diff auth.py auth.py.orig 106,111d105 < try: < password = str(str_) < except UnicodeEncodeError: < log.warning('rejecting non-ascii password') < return False < log.info(">>>>>>>>>>>>>>>>>> hash_string(%s)", repr(str_)) 113c107 < return hashlib.sha256(password).hexdigest() --- > return hashlib.sha256(str_).hexdigest() 116c110 < return bcrypt.hashpw(password, bcrypt.gensalt(10)) --- > return bcrypt.hashpw(str_, bcrypt.gensalt(10)) 136d129 < log.info(">>>>>>>>>>>>>>>>>> hash_check(%s)", repr(password)) 148d140 < log.info(">>>>>>>>>>>>>>>>>> get_crypt_password(%s)", repr(password))
Now it is OK.
Comment by Wise Kaa, on 2018-05-08 08:42
diff auth.py auth.py.orig 106,111d105 < try: < password = str(str_) < except UnicodeEncodeError: < log.warning('rejecting non-ascii password') < return False < log.info(">>>>>>>>>>>>>>>>>> hash_string(%s)", repr(str_)) 113c107 < return hashlib.sha256(password).hexdigest() --- > return hashlib.sha256(str_).hexdigest() 116c110 < return bcrypt.hashpw(password, bcrypt.gensalt(10)) --- > return bcrypt.hashpw(str_, bcrypt.gensalt(10)) 136d129 < log.info(">>>>>>>>>>>>>>>>>> hash_check(%s)", repr(password)) 148d140 < log.info(">>>>>>>>>>>>>>>>>> get_crypt_password(%s)", repr(password))
Comment by Wise Kaa, on 2018-05-08 09:27
Corrected:
diff auth.py auth.py.orig 106,111d1054-STABLE (WEB) #3 r328435: Fri Jan 26 16:30:17 MSK 2018 < try:]# mc < password = str(str_) < except UnicodeEncodeError: < log.warning('rejecting non-ascii password') < return False < log.info(">>>>>>>>>>>>>>>>>> hash_string(%s)", repr(str_)) 113c107 < return hashlib.sha256(password).hexdigest() --- > return hashlib.sha256(str_).hexdigest() 116c110 < return bcrypt.hashpw(password, bcrypt.gensalt(10)) --- > return bcrypt.hashpw(str_, bcrypt.gensalt(10)) 136,141d129 < try: < hashed = str(hashed) < except UnicodeEncodeError: < log.warning('rejecting non-ascii hashed password') < return False < log.info(">>>>>>>>>>>>>>>>>> hash_check(%s)", repr(password)) 153d140 < log.info(">>>>>>>>>>>>>>>>>> get_crypt_password(%s)", repr(password))
Comment by Thomas De Schampheleire, on 2018-05-08 10:29
In unified diff, the total change you did seems to be:
diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py --- a/kallithea/lib/auth.py +++ b/kallithea/lib/auth.py @@ -103,11 +103,17 @@ class KallitheaCrypto(object): :param password: password to hash """ + try: + password = str(str_) + except UnicodeEncodeError: + log.warning('rejecting non-ascii password') + return False + log.info(">>>>>>>>>>>>>>>>>> hash_string(%s)", repr(str_)) if is_windows: - return hashlib.sha256(str_).hexdigest() + return hashlib.sha256(password).hexdigest() elif is_unix: import bcrypt - return bcrypt.hashpw(str_, bcrypt.gensalt(10)) + return bcrypt.hashpw(password, bcrypt.gensalt(10)) else: raise Exception('Unknown or unsupported platform %s' \ % __platform__) @@ -127,6 +133,12 @@ class KallitheaCrypto(object): except UnicodeEncodeError: log.warning('rejecting non-ascii password') return False + try: + hashed = str(hashed) + except UnicodeEncodeError: + log.warning('rejecting non-ascii hashed password') + return False + log.info(">>>>>>>>>>>>>>>>>> hash_check(%s)", repr(password)) if is_windows: return hashlib.sha256(password).hexdigest() == hashed elif is_unix: @@ -138,6 +150,7 @@ class KallitheaCrypto(object): def get_crypt_password(password): + log.info(">>>>>>>>>>>>>>>>>> get_crypt_password(%s)", repr(password)) return KallitheaCrypto.hash_string(password)
Where the real change is to also verify the second parameter of hash_check.
It puzzles me a bit of what was really failing in the original situation. For registration, only hash_check seems to be used, at least that is in your traceback, and you showed the same problem with my first (corrected) patch.
Without changes (back to the original situation), do you see the same problem with any username password combination, e.g. 'foobar':'barfoo' ?
Comment by Wise Kaa, on 2018-05-08 11:52
Yes, i will foobar:barfoo, but this is not work. Now it is OK with your/my patches.
Comment by Mads Kiilerich, on 2018-05-08 13:59
Why was the issue closed? It hasn't been fixed upstream?
Also, can you confirm that you are running in an environment where LANG=C?
Comment by Thomas De Schampheleire, on 2018-05-13 19:22
Reopening issue until it has been fixed in the upstream code.
Comment by Thomas De Schampheleire, on 2018-05-13 19:24
@wisekaa03 Could you check the locale settings in the terminal in which you start Kallithea? E.g. by running:
env | grep LANG env | grep LC_
Comment by Richard H., on 2018-12-16 01:29
Hi there!
I just stumbled upon this problem. And I seem to have found the culprit - by incident.
Dec 16 01:43:06 pkg: py27-py-bcrypt-0.3 deinstalled
Dec 16 01:43:16 pkg: py27-bcrypt-3.1.4_1 installed
I just updated pkg and it changed my versions! So it seems there is a mismatch between ports version and pkg version of py27-bcrypt. I restored the package from ports and all is well again. When I installed kallithea, it chose this version after all.
Using FreeBSD 10.4-RELEASE too by the way.
Comment by Mads Kiilerich, on 2018-12-16 23:24
Oh. Right. These two projects both provide a 'bcrypt' module. But they should also conflict. So weird that despite setup.py requiring bcrypt >= 3.1.0, at runtime it ended up using py-bcrypt 0.3 .
Since the "right" bcrypt has __version__
and the other doesn't, we could perhaps add an
assert getattr(bcrypt, "__version__", '').split(".", 2)[:2] == ["3", "1"]
or
assert getattr(bcrypt, "__version__", '').startswith("3.1.")
Comment by Richard H., on 2018-12-20 11:00
It seems the error just happens, when the update happens without restarting the service. When trying to restart it, the dependency check fails. Well, FreeBSD is quite behind as well, just wanted to share my insight so if anybody else stumbles, the information will be there :)
Comment by Thomas De Schampheleire, on 2018-12-25 18:57
@chainria So it seems you are not using a virtualenv, but rather are relying on system packages, is that correct?
@kiilerix An assert like you proposed could be done. But we'd need to reference it from the setup.py dependency list to keep them in sync. More generally though, this problem could happen with every package: someone could update a package to a version outside of the supported range.
Comment by Richard H., on 2018-12-27 07:45
@patrickdepinguin Yes, that's right. The port did not install using a virtualenv and since it worked, I never gave it much thought for now. The dependencies weren't heavy either. I might switch to a virtualenv later, but as of right now I am quite new to Python.