The ucam_webauth module implements version 3 of the WAA to WLS protocol.
It is not set up to talk to a specific WAA (i.e., Raven), and subclassing this modules’ classes is required to make it functional (see raven).
The protocol is implemented as defined at https://raven.cam.ac.uk/project/waa2wls-protocol.txt at the time of writing (though that URL may have since been replaced with a newer version). A copy of wawa2wls-protocol.txt is included with python-raven, and more information can be found at https://raven.cam.ac.uk/project/.
AuthenticationType and Status instances used as constants in requests and responses
They compare equal with their corresponding integers (for status codes) and strings (for atypes).
A dict mapping status.code (i.e., the integer status code) to the relevant status object
An Authentication Type
This class exists to create the ucam_webauth.AUTH_PWD constant.
the name by which Ucam-webauth knows it
a sentence describing it
Note that comparing an AuthenticationType object with a str (or another AuthenticationType object) will compare the name attribute only. Further, str(atype) == atype.name.
A WLS response Status
a (three digit) integer
short name for the status
description: a sentence describing the status
Note that comparing a Status object with an integer (or another Status object) will compare the code attribute only. Further, int(status_object) == status_object.code
A Request to the WLS
Parameters: |
|
---|
All parameters are available as attributes as of Request object, once created.
The ‘msg’ and ‘desc’ parameters are restricted to printable ASCII characters (0x20 - 0x7e). The WLS will convert ‘<’ and ‘>’ to ‘<’ and ‘>’ before using either string in HTML, preventing the inclusion of markup. However, it does not touch ‘&’, so HTML character and numeric entities may be used to represent other characters.
If encode_strings is True, & will be escaped to &, and non-ascii characters in msg and desc will be converted to their numeric entities.
Otherwise, it is up to you to encode your strings. An error will be raised if msg or desc contain non-printable-ASCII characters.
The ucam-webauth protocol does not specify any restrictions on the content of params. However, awful things may happen if you put arbitrary binary data in here. The Raven server appears to interpret non-ascii contents as latin-1, turn them into html entities in order to put them in a hidden HTML input element, then turn them back into (hopefully) the same binary data to be returned in the Response. As a result it outright rejects ‘params’ containing bytes below 0x20, and has the potential to go horribly wrong and land you in encoding hell.
Basically, you probably want to base64 params before giving it to a Request object.
A Response from the WLS
Constructed by parsing string, the ‘encoded response string’ from the WLS.
The Response class has the following attributes, which must be set by subclassing it (see raven.Response):
A set of str objects
The ptags attribute is set to this value if the version of the response is less than 3
A dict mapping key identifiers (kid) to a RSA public key (which must be an object with a verify(digest, signature) method that returns a bool)
A Response object has the following attributes:
Always present
response protocol version (int)
a text message describing the status of the authentication request, suitable for display to the end-user (str)
response creation time (datetime, timezone naive - the values are UTC)
an “identifier” for the response. (int)
The tuple (issue, id) is guaranteed to be unique
the value of url supplied in the request, or equivalently, the URL to which this response was delivered (str)
shorthand for status == STATUS_SUCCESS (bool)
a copy of params from the request (str)
whether the signature was present and has been verified (bool)
Note that a present but invalid signature will produce an exception when parsed.
Present if authentication was successful, otherwise ``None``:
the authenticated identity of the user (str)
attributes or properties of the principal (frozenset of str objects)
method of authentication used (AuthenticationType constant, or None)
If authentication was not established by interaction (i.e., the client was already authenticated) then auth is None
previous successful authentication types used (frozenset of AuthenticationType constants)
sso will not be the empty set if auth is None
Optional if authentication was successful, otherwise ``None``:
remaining life of the user’s WLS session (int, in seconds)
Required if signed is True:
identifies the RSA key used to sign the request (str)
This module provides glue to make using python-raven with Flask easy
An instance of this class decorates views to add authentication.
To use it, you’ll need to subclass it and set response_class, request_class and logout_url (see raven.flask_glue.AuthDecorator). Then:
auth_decorator = AuthDecorator() # settings, e.g., desc="..." go here
@app.route("/some_url")
@auth_decorator
def my_view():
return "You are " + auth_decorator.principal
Or to require users be authenticated for all views:
app.before_request(auth_decorator.before_request)
Note that since it uses flask.session, you’ll need to set app.secret_key.
We need to be able to reliably determine the hostname of the current website. This is retrieved from flask.Request.url. By default, Werkzeug will respect the value of a X-Forwarded-Host header, which means that a man-in-the-middle can have someone authenticate to their website, and forward the response from the WLS on to you. You must either set flask.Request.trusted_hosts, for example like so:
class R(flask.Request):
trusted_hosts = {'www.danielrichman.co.uk'}
app.request_class = R
... or sanitise both the Host header and the X-Forwarded-Host header in your web-server. If you choose the second option, set can_trust_request_host.
This tries to emulate the feel of applying mod_ucam_webauth to a file.
The decorator wraps the view in a function that calls before_request() first, calling the original view function if it does not return a redirect or abort.
You may wish to catch the 401 and 403 aborts with app.errorhandler.
The principal, their ptags, the issue and life from the WLS are available as attributes of the AuthDecorator object (magic properties that retrieve the current values from flask.session). Further, the attributes expires and expires_all give information on when the ucam_webauth session will expire.
For the desc, aauth, iact, msg parameters, see ucam_webauth.Request.
Note that the max_life, use_wls_life and inactive_timeout parameters deal with the ucam_webauth session only; they only affect flask.session["_ucam_webauth"]. Flask’s session expiry, cookie lifetimes, etc. are independent.
Parameters: |
|
---|
More complex customisation is possible:
override check_authorised() to do more complex checking than require_principal, require_ptags (note that this replaces checking require_principal, require_ptags)
override session_new()
The AuthDecorator only touches flask.session["_ucam_webauth"]. If you’ve saved other (important) things to the session object, you may want to clear them out when the state changes.
You can do this by subclassing and overriding session_new. It is called whenever a response is received from the WLS, except if the response is a successful re-authentication after session expiry, with the same principal and ptags as before.
To log the user out, call logout(), which will clear the session state. Further, logout() returns a flask.redirect() to the Raven logout page. Be aware that the default flask session handlers are susceptible to replay attacks.
POST requests: Since it will redirect to the WLS and back, the auth decorator will discard any POST data in the process. You may wish to either work around this (by subclassing and saving it somewhere before redirecting) or ensure that when it returns (with a GET request) to the URL, a sensible page is displayed (the form, or an error message).
Wraps view_function with the auth decorator
(AuthDecorator objects are callable so that they can be used as function decorators.)
Calling it returns a ‘wrapper’ view function that calls request() first.
The current ptags, or None
When the last WLS response was issued
issue is converted to a unix timestamp (int), rather than the datetime object used by ucam_webauth.Response. (issue is None if there is no current session.)
A list of all things that could cause the current auth. to expire
A list of (str, int unix timestamp) tuples; (reason, when).
reason will be one of “config max life”, “wls life” or “inactive”.
The “main” method
Returns None, if the request should proceed to the actual view function.
Check if an authenticated user is authorised.
The default implementation requires the principal to be in the whitelist require_principal (if it is not None, in which case any principal is allowed) and the intersection of require_ptags and ptags to be non-empty (unless require_ptags is None, in which case any ptags (or no ptags at all) is permitted).
Note that the default value of require_ptags in raven.flask_glue.AuthDecorator is {"current"}.