@@ -60,6 +60,22 @@ def my_view():
6060 Note that since it uses flask.session, you'll need to set
6161 :attr:`app.secret_key`.
6262
63+ We need to be able to reliably determine the hostname of the current
64+ website. This is retrieved from :attr:`flask.Request.url`.
65+ By default, Werkzeug will respect the value of a ``X-Forwarded-Host``
66+ header, which means that a man-in-the-middle can have someone authenticate
67+ to *their* website, and forward the response from the WLS on to you.
68+ You must either set :attr:`flask.Request.trusted_hosts`, for example
69+ like so::
70+
71+ class R(flask.Request):
72+ trusted_hosts = {'www.danielrichman.co.uk'}
73+ app.request_class = R
74+
75+ ... or sanitise both the `Host` header *and* the `X-Forwarded-Host`
76+ header in your web-server. If you choose the second option, set
77+ `can_trust_request_host`.
78+
6379 This tries to emulate the feel of applying mod_ucam_webauth to a file.
6480
6581 The decorator wraps the view in a function that calls
@@ -106,6 +122,10 @@ def my_view():
106122 :type require_ptags: :class:`set` of :class:`str`, or ``None``
107123 :param require_ptags: require the ptags to contain `any` string in
108124 `require_ptags` (i.e., non empty intersection)
125+ :type can_trust_request_host: :class:`bool`
126+ :param can_trust_request_host: Can we trust the hostname in
127+ ``request.url``?
128+ (see :ref:`checking-response-values`)
109129
110130 More complex customisation is possible:
111131
@@ -149,7 +169,8 @@ def __init__(self, desc=None, aauth=None, iact=None, msg=None,
149169 max_life = 7200 , use_wls_life = False ,
150170 inactive_timeout = None , issue_bounds = (15 ,5 ),
151171 require_principal = None ,
152- require_ptags = frozenset (["current" ])):
172+ require_ptags = frozenset (["current" ]),
173+ can_trust_request_host = False ):
153174 self .desc = desc
154175 self .aauth = aauth
155176 self .iact = iact
@@ -160,6 +181,7 @@ def __init__(self, desc=None, aauth=None, iact=None, msg=None,
160181 self .issue_bounds = issue_bounds
161182 self .require_principal = require_principal
162183 self .require_ptags = require_ptags
184+ self .can_trust_request_host = can_trust_request_host
163185
164186 def __call__ (self , view_function ):
165187 """
@@ -423,6 +445,11 @@ def _check_url(self, wls_response_url):
423445 redirected after authentication.
424446 """
425447
448+ if not self .can_trust_request_host and request .trusted_hosts is None :
449+ raise RuntimeError ("Either set request.trusted_hosts, or sanitise "
450+ "Host/X-Forwarded-Host headers and pass "
451+ "can_trust_request_host = True" )
452+
426453 actual_url = request .url
427454
428455 # note: mod_ucam_webauth simply strips everything up to a ?
0 commit comments