Bowe Strickland
2018-10-26 7477177e84424ccf92c1c6a8c80da2ffb1a6d3f5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
:mod:`repoze.who` Use Cases
===========================
 
How should an application interact with :mod:`repoze.who`?  There are three
main scenarios:
 
Middleware-Only Use Cases
-------------------------
 
Examples of using the :mod:`repoze.who` middleware, without explicitly
using its API.
 
 
Simple:  Bug Tracker with ``REMOTE_USER``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
This application expects the ``REMOTE_USER`` variable to be set by
the middleware for authenticated requests.  It allows the middleware to
handle challenging the user when needed.
 
In protected views, such as those which allow creating or following up
to bug reports:
 
- Check ``environ['REMOTE_USER']`` to get the authenticated user, and apply
  any application-specific policy (who is allowed to edit).
 
  - If the access check fails because the user is not yet authenticated,
    return an 401 Unauthorized response.
 
  - If the access check fails for authenticated users, return a
    403 Forbidden response.
 
Note that the application here doesn't depend on :mod:`repoze.who` at
all:  it would work identically if run behind Apache's ``mod_auth``.  The
``Trac`` application works exactly this way.
 
The middleware can be configured to suit the policy required for the
site, e.g.:
 
- challenge / identify using HTTP basic authentication
 
- authorize via an ``.htaccces``-style file.
 
 
More complex:  Wiki with ``repoze.who.identity``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
This application use the ``repoze.who.identity`` variable set in the
WSGI environment by the middleware for authenticated requests.  The application
still allows the middleware to handle challenging the user when needed.
 
The only difference from the previous example is that protected views,
such as those which allow adding or editing wiki pages, can use the extra
metadata stored inside ``environ['repoze.who.identity']`` (a mapping) to
make authorization decisions:  such metadata might include groups or roles
mapped by the middleware onto the user.
 
 
API-Only Use Cases
------------------
 
Examples of using the :mod:`repoze.who` API without its middleware.
 
 
Simple:   Wiki with its own login and logout views.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
This application uses the :mod:`repoze.who` API to compute the authenticated
user, as well as using its ``remember`` API to set headers for cookie-based
authentication.
 
In each view:
 
- Call ``api.authenticate`` to get the authenticated user.
 
- Show a ``login`` link for non-authenticated requests.
 
- Show a ``logout`` link for authenticated requests.
 
- Don't show "protected" links for non-authenticated requests.
 
In protected views, such as those which allow adding or editing
wiki pages:
 
- Call ``api.authenticate`` to get the authenticated user;  check
  the metadata about the user (e.g., any appropriate roles or groups)
  to verify access.
 
  - If the access check fails because the user is not yet authenticated,
    redirect to the ``login`` view, with a ``came_from`` value of the
    current URL.
 
  - If the access check fails for authenticated users, return a
    403 Forbidden response.
 
In the login view:
 
- For ``GET`` requests, show the login form.
 
- For ``POST`` requests, validate the login and password from the form.
  If successful, call ``api.remember``, and append the returned headers to
  your response, which may also contain, e.g., a ``Location`` header for
  a redirect to the ``came_from`` URL.  In this case, there will be
  no authenticator plugin which knows about the login / password at all.
 
In the logout view:
 
- Call ``api.forget`` and append the headers to your response, which may
  also contain, e.g., a ``Location`` header for a redirect to the
  ``came_from`` URL after logging out.
 
 
More complex:  multiple applications with "single sign-on"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
In this scenario, authentication is "federated" across multiple applications,
which delegate to a central "login application."  This application verifies
credentials from the user, and then uses headers or other tokens to
communicate the verified identity to the delegating application.
 
In the login application:
 
- The SSO login application works just like the login view described above:
  the difference is that the configured identifier plugins must emit
  headers from ``remember`` which can be recognized by their counterparts
  in the other apps.
 
In the non-login applications:
 
- Challenge plugins here must be configured to implement the specific
  SSO protocol, e.g. redirect to the login app with information in the
  query string (other protocols might differ).
 
- Identifer plugins must be able to "crack" / consume whatever tokens are
  returned by the SSO login app.
 
- Authenticators will normally be no-ops (e.g., the ``auth_tkt`` plugin
  used as an authenticator).
 
Hybrid Use Cases
----------------
 
Examples of using the :mod:`repoze.who` API in conjuntion with its middleware.
 
Most complex:  integrate Trac and the wiki behind SSO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
This example extends the previous one, but adds into the mix the
requirement that one or more of the non-login applications (e.g., Trac)
be used "off the shelf," without modifying them.  Such applications can
be plugged into the same SSO regime, with the addition of the
:mod:``repoze.who`` middleware as an adapter to bridge the gap (e.g.,
to turn the SSO tokens into the ``REMOTE_USER`` required by Trac).
 
In this scenario, the middleware would be configured identically to the
API used in applications which do not need the middleware shim.