Repository: Kinto/kinto

Issue:
exception in accounts plugin authentication: Unicode-objects must be encoded before hashing
Running a fresh docker image built from master (36dbcc0) with postgresql storage

After:
```
echo '{"data": {"password": "PASSWD"}}' | http PUT http://localhost:8889/v1/accounts/eric
```
Running
```
http GET http://localhost:8889/v1/ --auth eric:coucou3333
```
Triggers following exception :
```
Unicode-objects must be encoded before hashing 
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pyramid/tweens.py", line 22, in excview_tween
    response = handler(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/__init__.py", line 119, in tm_tween
    reraise(*exc_info)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/compat.py", line 15, in reraise
    raise value
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/__init__.py", line 98, in tm_tween
    response = handler(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/router.py", line 155, in handle_request
    view_name
  File "/usr/local/lib/python3.5/dist-packages/pyramid/view.py", line 612, in _call_view
    response = view_callable(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/config/views.py", line 181, in __call__
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 389, in attr_view
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 367, in predicate_wrapper
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 438, in rendered_view
    result = view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 147, in _requestonly_view
    response = view(request)
  File "/usr/local/lib/python3.5/dist-packages/cornice/service.py", line 493, in wrapper
    response = view_(request)
  File "/code/kinto/core/views/hello.py", line 45, in get_hello
    if Authenticated in request.effective_principals:
  File "/usr/local/lib/python3.5/dist-packages/pyramid/security.py", line 375, in effective_principals
    return policy.effective_principals(self)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_multiauth/__init__.py", line 119, in effective_principals
    userid = policy.authenticated_userid(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/authentication.py", line 92, in authenticated_userid
    callback_ok = self.callback(userid, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/authentication.py", line 1123, in callback
    return self.check(username, password, request)
  File "/code/kinto/plugins/accounts/authentication.py", line 18, in account_check
    if hashed == bcrypt.hashpw(pwd_str, hashed):
  File "/usr/local/lib/python3.5/dist-packages/bcrypt/__init__.py", line 62, in hashpw
    raise TypeError("Unicode-objects must be encoded before hashing")
```

It is fixed by encoding the value received from the session at [this line in authentication.py](https://github.com/Kinto/kinto/blob/master/kinto/plugins/accounts/authentication.py#L16):
```
 hashed = existing['password'].encode(encoding='utf8')
```

exception in accounts plugin authentication: Unicode-objects must be encoded before hashing
Running a fresh docker image built from master (36dbcc0) with postgresql storage

After:
```
echo '{"data": {"password": "PASSWD"}}' | http PUT http://localhost:8889/v1/accounts/eric
```
Running
```
http GET http://localhost:8889/v1/ --auth eric:coucou3333
```
Triggers following exception :
```
Unicode-objects must be encoded before hashing 
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pyramid/tweens.py", line 22, in excview_tween
    response = handler(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/__init__.py", line 119, in tm_tween
    reraise(*exc_info)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/compat.py", line 15, in reraise
    raise value
  File "/usr/local/lib/python3.5/dist-packages/pyramid_tm/__init__.py", line 98, in tm_tween
    response = handler(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/router.py", line 155, in handle_request
    view_name
  File "/usr/local/lib/python3.5/dist-packages/pyramid/view.py", line 612, in _call_view
    response = view_callable(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/config/views.py", line 181, in __call__
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 389, in attr_view
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 367, in predicate_wrapper
    return view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 438, in rendered_view
    result = view(context, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/viewderivers.py", line 147, in _requestonly_view
    response = view(request)
  File "/usr/local/lib/python3.5/dist-packages/cornice/service.py", line 493, in wrapper
    response = view_(request)
  File "/code/kinto/core/views/hello.py", line 45, in get_hello
    if Authenticated in request.effective_principals:
  File "/usr/local/lib/python3.5/dist-packages/pyramid/security.py", line 375, in effective_principals
    return policy.effective_principals(self)
  File "/usr/local/lib/python3.5/dist-packages/pyramid_multiauth/__init__.py", line 119, in effective_principals
    userid = policy.authenticated_userid(request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/authentication.py", line 92, in authenticated_userid
    callback_ok = self.callback(userid, request)
  File "/usr/local/lib/python3.5/dist-packages/pyramid/authentication.py", line 1123, in callback
    return self.check(username, password, request)
  File "/code/kinto/plugins/accounts/authentication.py", line 18, in account_check
    if hashed == bcrypt.hashpw(pwd_str, hashed):
  File "/usr/local/lib/python3.5/dist-packages/bcrypt/__init__.py", line 62, in hashpw
    raise TypeError("Unicode-objects must be encoded before hashing")
```

It is fixed by encoding the value received from the session at [this line in authentication.py](https://github.com/Kinto/kinto/blob/master/kinto/plugins/accounts/authentication.py#L16):
```
 hashed = existing['password'].encode(encoding='utf8')
```



Discussion:
Would you like to file a PR to fix this?
Would you like to file a PR to fix this?

Resolving patch:
diff --git a/kinto/plugins/accounts/authentication.py b/kinto/plugins/accounts/authentication.py
--- a/kinto/plugins/accounts/authentication.py
+++ b/kinto/plugins/accounts/authentication.py
@@ -13,7 +13,7 @@ def account_check(username, password, request):
     except storage_exceptions.RecordNotFoundError:
         return None
 
-    hashed = existing['password']
+    hashed = existing['password'].encode(encoding='utf-8')
     pwd_str = password.encode(encoding='utf-8')
     if hashed == bcrypt.hashpw(pwd_str, hashed):
         return True  # Match! Return anything but None.
diff --git a/kinto/plugins/accounts/views.py b/kinto/plugins/accounts/views.py
--- a/kinto/plugins/accounts/views.py
+++ b/kinto/plugins/accounts/views.py
@@ -89,9 +89,11 @@ def collection_post(self):
     def process_record(self, new, old=None):
         new = super(Account, self).process_record(new, old)
 
-        # Store password safely in database.
+        # Store password safely in database as str
+        # (bcrypt.hashpw returns base64 bytes).
         pwd_str = new["password"].encode(encoding='utf-8')
-        new["password"] = bcrypt.hashpw(pwd_str, bcrypt.gensalt())
+        hashed = bcrypt.hashpw(pwd_str, bcrypt.gensalt())
+        new["password"] = hashed.decode(encoding='utf-8')
 
         # Administrators can reach other accounts and anonymous have no
         # selected_userid. So do not try to enforce.


Test patch: