Michael Merickel
2018-04-24 7e2cc0d8b73880650b0a3d0b602fcaf3905ccd11
commit | author | age
d9c4cb 1 .. _qtut_authentication:
SP 2
b1b922 3 ==============================
e5c279 4 20: Logins with authentication
b1b922 5 ==============================
PE 6
b92a5f 7 Login views that authenticate a username and password against a list of users.
SP 8
b1b922 9
PE 10 Background
11 ==========
12
b92a5f 13 Most web applications have URLs that allow people to add/edit/delete content
SP 14 via a web browser. Time to add :ref:`security <security_chapter>` to the
15 application. In this first step we introduce authentication. That is, logging
16 in and logging out, using Pyramid's rich facilities for pluggable user storage.
b1b922 17
b92a5f 18 In the next step we will introduce protection of resources with authorization
SP 19 security statements.
20
b1b922 21
PE 22 Objectives
23 ==========
24
b92a5f 25 - Introduce the Pyramid concepts of authentication.
b1b922 26
b92a5f 27 - Create login and logout views.
b1b922 28
PE 29 Steps
30 =====
31
32 #. We are going to use the view classes step as our starting point:
33
34    .. code-block:: bash
35
187104 36     $ cd ..; cp -r view_classes authentication; cd authentication
29d12c 37
e5c279 38 #. Add ``bcrypt`` as a dependency in ``authentication/setup.py``:
29d12c 39
KY 40    .. literalinclude:: authentication/setup.py
e5c279 41     :language: python
d48884 42     :emphasize-lines: 4
29d12c 43     :linenos:
KY 44
e5c279 45 #. We can now install our project in development mode:
29d12c 46
KY 47    .. code-block:: bash
48
2c8511 49     $ $VENV/bin/pip install -e .
b1b922 50
PE 51 #. Put the security hash in the ``authentication/development.ini``
b92a5f 52    configuration file as ``tutorial.secret`` instead of putting it in the code:
b1b922 53
PE 54    .. literalinclude:: authentication/development.ini
55     :language: ini
56     :linenos:
57
b92a5f 58 #. Get authentication (and for now, authorization policies) and login route
SP 59    into the :term:`configurator` in ``authentication/tutorial/__init__.py``:
b1b922 60
PE 61    .. literalinclude:: authentication/tutorial/__init__.py
62     :linenos:
63
b92a5f 64 #. Create an ``authentication/tutorial/security.py`` module that can find our
SP 65    user information by providing an *authentication policy callback*:
b1b922 66
PE 67    .. literalinclude:: authentication/tutorial/security.py
68     :linenos:
69
70 #. Update the views in ``authentication/tutorial/views.py``:
71
72    .. literalinclude:: authentication/tutorial/views.py
73     :linenos:
74
75 #. Add a login template at ``authentication/tutorial/login.pt``:
76
77    .. literalinclude:: authentication/tutorial/login.pt
78     :language: html
79     :linenos:
80
b92a5f 81 #. Provide a login/logout box in ``authentication/tutorial/home.pt``:
b1b922 82
PE 83    .. literalinclude:: authentication/tutorial/home.pt
84     :language: html
85     :linenos:
86
87 #. Run your Pyramid application with:
88
89    .. code-block:: bash
90
187104 91     $ $VENV/bin/pserve development.ini --reload
b1b922 92
d749bf 93 #. Open http://localhost:6543/ in a browser.
b1b922 94
PE 95 #. Click the "Log In" link.
96
d48884 97 #. Submit the login form with the username ``editor`` and the password
b1b922 98    ``editor``.
PE 99
100 #. Note that the "Log In" link has changed to "Logout".
101
102 #. Click the "Logout" link.
103
104 Analysis
105 ========
106
b92a5f 107 Unlike many web frameworks, Pyramid includes a built-in but optional security
SP 108 model for authentication and authorization. This security system is intended to
109 be flexible and support many needs. In this security model, authentication (who
110 are you) and authorization (what are you allowed to do) are not just pluggable,
e5c279 111 but decoupled. To learn one step at a time, we provide a system that identifies
SP 112 users and lets them log out.
b1b922 113
b92a5f 114 In this example we chose to use the bundled :ref:`AuthTktAuthenticationPolicy
SP 115 <authentication_module>` policy. We enabled it in our configuration and
116 provided a ticket-signing secret in our INI file.
b1b922 117
b92a5f 118 Our view class grew a login view. When you reached it via a ``GET`` request, it
SP 119 returned a login form. When reached via ``POST``, it processed the submitted
120 username and password against the "groupfinder" callable that we registered in
121 the configuration.
e5c279 122
SP 123 The function ``hash_password`` uses a one-way hashing algorithm with a salt on
124 the user's password via ``bcrypt``, instead of storing the password in plain
125 text. This is considered to be a "best practice" for security.
126
127 .. note::
128     There are alternative libraries to ``bcrypt`` if it is an issue on your
129     system. Just make sure that the library uses an algorithm approved for
130     storing passwords securely.
131
132 The function ``check_password`` will compare the two hashed values of the
133 submitted password and the user's password stored in the database. If the
134 hashed values are equivalent, then the user is authenticated, else
135 authentication fails.
b1b922 136
b92a5f 137 In our template, we fetched the ``logged_in`` value from the view class. We use
SP 138 this to calculate the logged-in user, if any. In the template we can then
139 choose to show a login link to anonymous visitors or a logout link to logged-in
140 users.
b1b922 141
b92a5f 142
SP 143 Extra credit
b1b922 144 ============
PE 145
146 #. What is the difference between a user and a principal?
147
148 #. Can I use a database behind my ``groupfinder`` to look up principals?
149
b92a5f 150 #. Once I am logged in, does any user-centric information get jammed onto each
SP 151    request? Use ``import pdb; pdb.set_trace()`` to answer this.
b1b922 152
2033ee 153 .. seealso:: See also :ref:`security_chapter`,
e5c279 154    :ref:`AuthTktAuthenticationPolicy <authentication_module>`, `bcrypt
7e2cc0 155    <https://pypi.org/project/bcrypt/>`_