Keith Yang
2016-07-16 8a1892b904e736fb5edfd91e109469184f9d3017
Add one-way password hash to security example in Quick Tutorial.
(cherry picked from commit 29d12cd)
7 files modified
75 ■■■■ changed files
docs/quick_tutorial/authentication.rst 23 ●●●●● patch | view | raw | blame | history
docs/quick_tutorial/authentication/setup.py 3 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authentication/tutorial/security.py 16 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authentication/tutorial/views.py 7 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authorization/setup.py 3 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authorization/tutorial/security.py 16 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authorization/tutorial/views.py 7 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authentication.rst
@@ -34,6 +34,17 @@
   .. code-block:: bash
    $ cd ..; cp -r view_classes authentication; cd authentication
#. This step depends on bcrypt_, so add it as a dependency in
   ``authentication/setup.py``:
   .. literalinclude:: authentication/setup.py
    :linenos:
#. Now we can activate the development-mode distribution:
   .. code-block:: bash
    $ $VENV/bin/pip install -e .
#. Put the security hash in the ``authentication/development.ini``
@@ -103,6 +114,11 @@
<authentication_module>` policy. We enabled it in our configuration and
provided a ticket-signing secret in our INI file.
The function ``hash_password`` hashes user's password by bcrypt_ instead of
storing password in plain text directly as a best practice [1]_. And function
``check_password`` will compare the hashed value of the submitted password
against the hashed value of the user's password.
Our view class grew a login view. When you reached it via a ``GET`` request, it
returned a login form. When reached via ``POST``, it processed the submitted
username and password against the "groupfinder" callable that we registered in
@@ -126,3 +142,10 @@
.. seealso:: See also :ref:`security_chapter`,
   :ref:`AuthTktAuthenticationPolicy <authentication_module>`.
.. _bcrypt: https://pypi.python.org/pypi/bcrypt
.. [1] We are using the bcrypt_ package from PyPI to hash our passwords
       securely. There are other one-way hash algorithms for passwords if
       bcrypt is an issue on your system. Just make sure that it's an
       algorithm approved for storing passwords versus a generic one-way hash.
docs/quick_tutorial/authentication/setup.py
@@ -2,7 +2,8 @@
requires = [
    'pyramid',
    'pyramid_chameleon'
    'pyramid_chameleon',
    'bcrypt'
]
setup(name='tutorial',
docs/quick_tutorial/authentication/tutorial/security.py
@@ -1,5 +1,17 @@
USERS = {'editor': 'editor',
         'viewer': 'viewer'}
import bcrypt
def hash_password(pw):
    pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
    return pwhash.decode('utf8')
def check_password(pw, hashed_pw):
    expected_hash = hashed_pw.encode('utf8')
    return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
USERS = {'editor': hash_password('editor'),
         'viewer': hash_password('viewer')}
GROUPS = {'editor': ['group:editors']}
docs/quick_tutorial/authentication/tutorial/views.py
@@ -9,7 +9,10 @@
    view_defaults
    )
from .security import USERS
from .security import (
    USERS,
    check_password
)
@view_defaults(renderer='home.pt')
@@ -40,7 +43,7 @@
        if 'form.submitted' in request.params:
            login = request.params['login']
            password = request.params['password']
            if USERS.get(login) == password:
            if check_password(password, USERS.get(login)):
                headers = remember(request, login)
                return HTTPFound(location=came_from,
                                 headers=headers)
docs/quick_tutorial/authorization/setup.py
@@ -2,7 +2,8 @@
requires = [
    'pyramid',
    'pyramid_chameleon'
    'pyramid_chameleon',
    'bcrypt'
]
setup(name='tutorial',
docs/quick_tutorial/authorization/tutorial/security.py
@@ -1,5 +1,17 @@
USERS = {'editor': 'editor',
         'viewer': 'viewer'}
import bcrypt
def hash_password(pw):
    pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
    return pwhash.decode('utf8')
def check_password(pw, hashed_pw):
    expected_hash = hashed_pw.encode('utf8')
    return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
USERS = {'editor': hash_password('editor'),
         'viewer': hash_password('viewer')}
GROUPS = {'editor': ['group:editors']}
docs/quick_tutorial/authorization/tutorial/views.py
@@ -10,7 +10,10 @@
    forbidden_view_config
    )
from .security import USERS
from .security import (
    USERS,
    check_password
)
@view_defaults(renderer='home.pt')
@@ -42,7 +45,7 @@
        if 'form.submitted' in request.params:
            login = request.params['login']
            password = request.params['password']
            if USERS.get(login) == password:
            if check_password(password, USERS.get(login)):
                headers = remember(request, login)
                return HTTPFound(location=came_from,
                                 headers=headers)