Tres Seaver
2012-03-18 6919cb8daf7c7f7291b8aa10a28334c1a61848e9
commit | author | age
6919cb 1 try:
TS 2     import urlparse
3 except ImportError: #pragma NO COVER Python >= 3.0
4     from urllib import parse as urlparse
c80261 5 import urllib
TS 6 import cgi
7
02a504 8 from webob.exc import HTTPFound
c80261 9 from zope.interface import implements
TS 10
11 from repoze.who.interfaces import IChallenger
6919cb 12 from repoze.who._compat import construct_url
TS 13 from repoze.who._compat import header_value
c80261 14
TS 15 class RedirectorPlugin(object):
16     """ Plugin for issuing challenges as redirects to a configured URL.
17
18     o If the ``reason_param`` option is configured, and the application has
19       supplied an ``X-Authorization-Failure-Reason`` header, the plugin
20       includes that reason in the query string of the redirected URL.
21     """
22     implements(IChallenger)
23     
24     def __init__(self,
25                  login_url,
26                  came_from_param='came_from',
27                  reason_param='reason',
28                  reason_header='X-Authorization-Failure-Reason',
29                 ):
30         self.login_url = login_url
31         self.came_from_param = came_from_param
c76058 32         if ((reason_param is None and reason_header is not None) or
TS 33             (reason_param is not None and reason_header is None)):
34             raise ValueError(
35                 "Must supply both 'reason_header' and 'reason_param', "
36                 "or neither one.")
c80261 37         self.reason_param = reason_param
TS 38         self.reason_header = reason_header
39         self._login_url_parts = list(urlparse.urlparse(login_url))
40
41     # IChallenger
42     def challenge(self, environ, status, app_headers, forget_headers):
43         if self.reason_param is not None or self.came_from_param is not None:
44             url_parts = self._login_url_parts[:]
45             query = url_parts[4]
46             query_elements = cgi.parse_qs(query)
c76058 47             if self.reason_param is not None:
TS 48                 reason = header_value(app_headers, self.reason_header)
49                 if reason:
50                     query_elements[self.reason_param] = reason
c80261 51             if self.came_from_param is not None:
TS 52                 query_elements[self.came_from_param] = construct_url(environ)
53             url_parts[4] = urllib.urlencode(query_elements, doseq=True)
54             login_url = urlparse.urlunparse(url_parts)
55         else:
56             login_url = self.login_url
57         headers = [('Location', login_url)] + forget_headers
58         cookies = [(h,v) for (h,v) in app_headers if h.lower() == 'set-cookie']
59         headers += cookies
60         return HTTPFound(headers=headers)
61
62 def make_plugin(login_url,
63                 came_from_param=None,
64                 reason_param=None,
65                 reason_header=None,
66                ):
67     if reason_header is not None and reason_param is None:
68         raise Exception("Can't set 'reason_header' without 'reason_param'.")
69
70     if reason_header is None and reason_param is not None:
71         reason_header='X-Authorization-Failure-Reason'
72
73     return RedirectorPlugin(login_url,
74                             came_from_param=came_from_param,
75                             reason_param=reason_param,
76                             reason_header=reason_header,
77                            )