1from tg.controllers.util import _build_url 2 3try: 4 from urlparse import urlparse, urlunparse, parse_qs 5except ImportError: #pragma: no cover 6 from urllib.parse import urlparse, urlunparse, parse_qs 7 8try: 9 from urllib import urlencode 10except ImportError: #pragma: no cover 11 from urllib.parse import urlencode 12 13from webob import Request 14from webob.exc import HTTPFound, HTTPUnauthorized 15from zope.interface import implementer 16 17from repoze.who.interfaces import IChallenger, IIdentifier 18 19@implementer(IChallenger, IIdentifier) 20class FastFormPlugin(object): 21 """ 22 Simplified and faster version of the repoze.who.friendlyforms 23 FriendlyForm plugin. The FastForm version works only with UTF-8 24 content which is the default for new WebOb versions. 25 """ 26 classifications = { 27 IIdentifier: ["browser"], 28 IChallenger: ["browser"], 29 } 30 31 def __init__(self, login_form_url, login_handler_path, post_login_url, 32 logout_handler_path, post_logout_url, rememberer_name, 33 login_counter_name=None): 34 """ 35 :param login_form_url: The URL/path where the login form is located. 36 :type login_form_url: str 37 :param login_handler_path: The URL/path where the login form is 38 submitted to (where it is processed by this plugin). 39 :type login_handler_path: str 40 :param post_login_url: The URL/path where the user should be redirected 41 to after login (even if wrong credentials were provided). 42 :type post_login_url: str 43 :param logout_handler_path: The URL/path where the user is logged out. 44 :type logout_handler_path: str 45 :param post_logout_url: The URL/path where the user should be 46 redirected to after logout. 47 :type post_logout_url: str 48 :param rememberer_name: The name of the repoze.who identifier which 49 acts as rememberer. 50 :type rememberer_name: str 51 """ 52 self.login_form_url = login_form_url 53 self.login_handler_path = login_handler_path 54 self.post_login_url = post_login_url 55 self.logout_handler_path = logout_handler_path 56 self.post_logout_url = post_logout_url 57 self.rememberer_name = rememberer_name 58 59 if not login_counter_name: 60 login_counter_name = '__logins' 61 self.login_counter_name = login_counter_name 62 63 # IIdentifier 64 def identify(self, environ): 65 path_info = environ['PATH_INFO'] 66 67 if path_info == self.login_handler_path: 68 query = self._get_form_data(environ) 69 70 try: 71 credentials = {'login': query['login'], 72 'password': query['password'], 73 'max_age':query.get('remember')} 74 except KeyError: 75 credentials = None 76 77 params = {} 78 if 'came_from' in query: 79 params['came_from'] = query['came_from'] 80 if self.login_counter_name is not None and self.login_counter_name in query: 81 params[self.login_counter_name] = query[self.login_counter_name] 82 83 destination = _build_url(environ, self.post_login_url, params=params) 84 environ['repoze.who.application'] = HTTPFound(location=destination) 85 return credentials 86 87 elif path_info == self.logout_handler_path: 88 query = self._get_form_data(environ) 89 came_from = query.get('came_from') 90 if came_from is None: 91 came_from = _build_url(environ, '/') 92 93 # set in environ for self.challenge() to find later 94 environ['came_from'] = came_from 95 environ['repoze.who.application'] = HTTPUnauthorized() 96 97 elif path_info in (self.login_form_url, self.post_login_url): 98 query = self._get_form_data(environ) 99 environ['repoze.who.logins'] = 0 100 101 if self.login_counter_name is not None and self.login_counter_name in query: 102 environ['repoze.who.logins'] = int(query[self.login_counter_name]) 103 del query[self.login_counter_name] 104 environ['QUERY_STRING'] = urlencode(query, doseq=True) 105 106 return None 107 108 # IChallenger 109 def challenge(self, environ, status, app_headers, forget_headers): 110 path_info = environ['PATH_INFO'] 111 112 # Configuring the headers to be set: 113 cookies = [(h,v) for (h,v) in app_headers if h.lower() == 'set-cookie'] 114 headers = forget_headers + cookies 115 116 if path_info == self.logout_handler_path: 117 params = {} 118 if 'came_from' in environ: 119 params.update({'came_from':environ['came_from']}) 120 destination = _build_url(environ, self.post_logout_url, params=params) 121 122 else: 123 came_from_params = parse_qs(environ.get('QUERY_STRING', '')) 124 params = {'came_from': _build_url(environ, path_info, came_from_params)} 125 destination = _build_url(environ, self.login_form_url, params=params) 126 127 return HTTPFound(location=destination, headers=headers) 128 129 # IIdentifier 130 def remember(self, environ, identity): 131 rememberer = self._get_rememberer(environ) 132 return rememberer.remember(environ, identity) 133 134 # IIdentifier 135 def forget(self, environ, identity): 136 rememberer = self._get_rememberer(environ) 137 return rememberer.forget(environ, identity) 138 139 def _get_rememberer(self, environ): 140 rememberer = environ['repoze.who.plugins'][self.rememberer_name] 141 return rememberer 142 143 def _get_form_data(self, environ): 144 request = Request(environ) 145 query = dict(request.GET) 146 query.update(request.POST) 147 return query 148 149 def __repr__(self): 150 return '<%s:%s %s>' % (self.__class__.__name__, self.login_handler_path, id(self)) 151