Tres Seaver
2017-12-20 a83610e170325e157726a4649923dff8ae303d12
commit | author | age
fdbab9 1 from zope.interface import Interface
CM 2
993216 3
TS 4 class IAPIFactory(Interface):
5     def __call__(environ):
6         """ environ -> IRepozeWhoAPI
7         """
8
9
10 class IAPI(Interface):
11     """ Facade for stateful invocation of underlying plugins.
12     """
13     def authenticate():
14         """ ->  {identity}
15
16         o Return an authenticated identity mapping, extracted from the
17         request environment.
18
19         o If no identity can be authenticated, return None.
20
21         o Identity will include at least a 'repoze.who.userid' key,
22         as well as any keys added by metadata plugins.
23         """
24
b482a1 25     def challenge(status='403 Forbidden', app_headers=()):
993216 26         """ -> wsgi application
TS 27         
28         o Return a WSGI application which represents a "challenge"
29         (request for credentials) in response to the current request.  
30         """
31
fd9f30 32     def remember(identity=None):
993216 33         """ -> [headers]
TS 34         
35         O Return a sequence of response headers which suffice to remember
36         the given identity.
fd9f30 37
TS 38         o If 'identity' is not passed, use the identity in the environment.
993216 39         """
TS 40
fd9f30 41     def forget(identity=None):
993216 42         """ -> [headers]
TS 43         
44         O Return a sequence of response headers which suffice to destroy
45         any credentials used to establish an identity.
fd9f30 46
TS 47         o If 'identity' is not passed, use the identity in the environment.
993216 48         """
TS 49
9a8e60 50     def login(credentials, identifier_name=None):
TS 51         """ -> (identity, headers)
52         
53         o This is an API for browser-based application login forms.
54         
55         o If 'identifier_name' is passed, use it to look up the identifier;
56           othewise, use the first configured identifier.
57
58         o Attempt to authenticate 'credentials' as though the identifier
59           had extracted them.
60           
61         o On success, 'identity' will be authenticated mapping, and 'headers'
62           will be "remember" headers.
63
64         o On failure, 'identity' will be None, and response_headers will be
65           "forget" headers.
66         """
67
924f24 68     def logout(identifier_name=None):
TS 69         """ -> (headers)
70         
71         o This is an API for browser-based application logout.
72         
73         o If 'identifier_name' is passed, use it to look up the identifier;
74           othewise, use the first configured identifier.
75
76         o Returned headers will be "forget" headers.
77         """
78
993216 79
515c69 80 class IPlugin(Interface):
TS 81     pass
993216 82
515c69 83
TS 84 class IRequestClassifier(IPlugin):
d85ba6 85     """ On ingress: classify a request.
CM 86     """
87     def __call__(environ):
7dfea7 88         """ environ -> request classifier string
CM 89
90         This interface is responsible for returning a string
91         value representing a request classification.
92
93         o 'environ' is the WSGI environment.
94         """
993216 95
d85ba6 96
515c69 97 class IChallengeDecider(IPlugin):
c51195 98     """ On egress: decide whether a challenge needs to be presented
CM 99     to the user.
d85ba6 100     """
c51195 101     def __call__(environ, status, headers):
CM 102         """ args -> True | False
7dfea7 103
CM 104         o 'environ' is the WSGI environment.
105
c51195 106         o 'status' is the HTTP status as returned by the downstream
CM 107           WSGI application.
7dfea7 108
c51195 109         o 'headers' are the headers returned by the downstream WSGI
CM 110           application.
7dfea7 111
c51195 112         This interface is responsible for returning True if
CM 113         a challenge needs to be presented to the user, False otherwise.
114         """
993216 115
d85ba6 116
515c69 117 class IIdentifier(IPlugin):
fdbab9 118
c51195 119     """
CM 120     On ingress: Extract credentials from the WSGI environment and
121     turn them into an identity.
122
123     On egress (remember): Conditionally set information in the response headers
124     allowing the remote system to remember this identity.
125
126     On egress (forget): Conditionally set information in the response
127     headers allowing the remote system to forget this identity (during
128     a challenge).
fdbab9 129     """
CM 130
c51195 131     def identify(environ):
CM 132         """ On ingress:
133
40a968 134         environ -> {   k1 : v1
fdbab9 135                        ,   ...
CM 136                        , kN : vN
c51195 137                        } | None
fdbab9 138
CM 139         o 'environ' is the WSGI environment.
140
c51195 141         o If credentials are found, the returned identity mapping will
40a968 142           contain an arbitrary set of key/value pairs.  If the
CM 143           identity is based on a login and password, the environment
144           is recommended to contain at least 'login' and 'password'
145           keys as this provides compatibility between the plugin and
146           existing authenticator plugins.  If the identity can be
147           'preauthenticated' (e.g. if the userid is embedded in the
148           identity, such as when we're using ticket-based
149           authentication), the plugin should set the userid in the
cb5426 150           special 'repoze.who.userid' key; no authenticators will be
40a968 151           asked to authenticate the identity thereafer.
fdbab9 152
c51195 153         o Return None to indicate that the plugin found no appropriate
CM 154           credentials.
d85ba6 155
c51195 156         o Only IIdentifier plugins which match one of the the current
CM 157           request's classifications will be asked to perform
158           identification.
c10c07 159
CM 160         o An identifier plugin is permitted to add a key to the
161           environment named 'repoze.who.application', which should be
162           an arbitrary WSGI application.  If an identifier plugin does
163           so, this application is used instead of the downstream
164           application set up within the middleware.  This feature is
165           useful for identifier plugins which need to perform
166           redirection to obtain credentials.  If two identifier
167           plugins add a 'repoze.who.application' WSGI application to
168           the environment, the last one consulted will"win".
fdbab9 169         """
7dfea7 170
c51195 171     def remember(environ, identity):
CM 172         """ On egress (no challenge required):
7dfea7 173
c51195 174         args -> [ (header-name, header-value), ...] | None
CM 175
176         Return a list of headers suitable for allowing the requesting
177         system to remember the identification information (e.g. a
178         Set-Cookie header).  Return None if no headers need to be set.
179         These headers will be appended to any headers returned by the
180         downstream application.
181         """
182
183     def forget(environ, identity):
184         """ On egress (challenge required):
185
186         args -> [ (header-name, header-value), ...] | None
187
188         Return a list of headers suitable for allowing the requesting
189         system to forget the identification information (e.g. a
190         Set-Cookie header with an expires date in the past).  Return
191         None if no headers need to be set.  These headers will be
192         included in the response provided by the challenge app.
193         """
194
993216 195
515c69 196 class IAuthenticator(IPlugin):
c51195 197
CM 198     """ On ingress: validate the identity and return a user id or None.
7dfea7 199     """
CM 200
c51195 201     def authenticate(environ, identity):
CM 202         """ identity -> 'userid' | None
7dfea7 203
CM 204         o 'environ' is the WSGI environment.
205
40a968 206         o 'identity' will be a dictionary (with arbitrary keys and
CM 207           values).
208  
c10c07 209         o The IAuthenticator should return a single user id (optimally
CM 210           a string) if the identity can be authenticated.  If the
211           identify cannot be authenticated, the IAuthenticator should
212           return None.
7dfea7 213
c51195 214         Each instance of a registered IAuthenticator plugin that
CM 215         matches the request classifier will be called N times during a
216         single request, where N is the number of identities found by
217         any IIdentifierPlugin instances.
40a968 218
CM 219         An authenticator must not raise an exception if it is provided
220         an identity dictionary that it does not understand (e.g. if it
221         presumes that 'login' and 'password' are keys in the
222         dictionary, it should check for the existence of these keys
223         before attempting to do anything; if they don't exist, it
224         should return None).
64ba13 225
TS 226         An authenticator is permitted to add extra keys to the 'identity'
227         dictionary (e.g., to save metadata from a database query, rather
228         than requiring a separate query from an IMetadataProvider plugin).
7dfea7 229         """
CM 230
993216 231
515c69 232 class IChallenger(IPlugin):
fdbab9 233
7dfea7 234     """ On egress: Conditionally initiate a challenge to the user to
CM 235         provide credentials.
236
237         Only challenge plugins which match one of the the current
238         response's classifications will be asked to perform a
239         challenge.
240     """
241
c51195 242     def challenge(environ, status, app_headers, forget_headers):
7dfea7 243         """ args -> WSGI application or None
fdbab9 244
CM 245         o 'environ' is the WSGI environment.
246
7dfea7 247         o 'status' is the status written into start_response by the
CM 248           downstream application.
fdbab9 249
c51195 250         o 'app_headers' is the headers list written into start_response by the
7dfea7 251           downstream application.
fdbab9 252
c51195 253         o 'forget_headers' is a list of headers which must be passed
CM 254           back in the response in order to perform credentials reset
255           (logout).  These come from the 'forget' method of
256           IIdentifier plugin used to do the request's identification.
257
7dfea7 258         Examine the values passed in and return a WSGI application
CM 259         (a callable which accepts environ and start_response as its
260         two positional arguments, ala PEP 333) which causes a
261         challenge to be performed.  Return None to forego performing a
262         challenge.
fdbab9 263         """
CM 264
0991c4 265
515c69 266 class IMetadataProvider(IPlugin):
b5a331 267     """On ingress: When an identity is authenticated, metadata
CM 268        providers may scribble on the identity dictionary arbitrarily.
c10c07 269        Return values from metadata providers are ignored.
0991c4 270     """
WM 271     
b5a331 272     def add_metadata(environ, identity):
CM 273         """
c10c07 274         Add metadata to the identity (which is a dictionary).  One
CM 275         value is always guaranteed to be in the dictionary when
276         add_metadata is called: 'repoze.who.userid', representing the
277         user id of the identity.  Availability and composition of
278         other keys will depend on the identifier plugin which created
279         the identity.
0991c4 280         """