def identify(self, environ): query = parse_dict_querystring(environ) # If the extractor finds a special query string on any request, # it will attempt to find the values in the input body. if query.get(self.login_form_qs): form = parse_formvars(environ) from StringIO import StringIO # XXX we need to replace wsgi.input because we've read it # this smells funny environ['wsgi.input'] = StringIO() form.update(query) try: login = form['login'] password = form['password'] except KeyError: return None del query[self.login_form_qs] environ['QUERY_STRING'] = urllib.urlencode(query) environ['repoze.who.application'] = HTTPFound( construct_url(environ)) credentials = {'login':login, 'password':password} max_age = form.get('max_age', None) if max_age is not None: credentials['max_age'] = max_age return credentials return None
def challenge(self, environ, status, app_headers, forget_headers): logger = environ.get("repoze.who.logger", "") logger.info("formplugin challenge") if app_headers: location = LOCATION(app_headers) if location: headers = list(app_headers) + list(forget_headers) return HTTPFound(headers=headers) query = parse_dict_querystring(environ) hidden = [] for key, val in query.items(): hidden.append(HIDDEN_PRE_LINE % ("_%s_" % key, val)) logger.info("hidden: %s", hidden) form = self.formbody or _DEFAULT_FORM form = form % "\n".join(hidden) if self.formcallable is not None: form = self.formcallable(environ) def auth_form(environ, start_response): content_length = CONTENT_LENGTH.tuples(str(len(form))) content_type = CONTENT_TYPE.tuples("text/html") headers = content_length + content_type + forget_headers start_response("200 OK", headers) return [form] return auth_form
def identify(self, environ): path_info = environ['PATH_INFO'] query = parse_dict_querystring(environ) if path_info == self.logout_handler_path: # we've been asked to perform a logout form = parse_formvars(environ) form.update(query) referer = environ.get('HTTP_REFERER', '/') environ['repoze.who.application'] = HTTPUnauthorized() return None elif path_info == self.login_handler_path: # we've been asked to perform a login form = parse_formvars(environ) form.update(query) try: max_age = form.get('max_age', None) credentials = { 'login': form['login'], 'password': form['password'], 'realm': form['realm'], } except KeyError: credentials = None if credentials is not None: max_age = form.get('max_age', None) if max_age is not None: credentials['max_age'] = max_age referer = environ.get('HTTP_REFERER', '/') environ['repoze.who.application'] = HTTPFound(referer) return credentials
def identify(self, environ): query = parse_dict_querystring(environ) # If the extractor finds a special query string on any request, # it will attempt to find the values in the input body. if query.get(self.login_form_qs): form = parse_formvars(environ) from StringIO import StringIO # XXX we need to replace wsgi.input because we've read it # this smells funny environ['wsgi.input'] = StringIO() form.update(query) credentials = self._getCredentials(form) del query[self.login_form_qs] environ['QUERY_STRING'] = urllib.urlencode(query) environ['repoze.who.application'] = HTTPFound( construct_url(environ)) if 'login' not in credentials or 'password' not in credentials: return None return credentials return None
def challenge(self, environ, status, app_headers, forget_headers): ''' the challenge method is implemented here to supress the came_from query_attribute, which is not welcomed here :-) ''' reason = header_value(app_headers, 'X-Authorization-Failure-Reason') # split the login url in host, url, ? , query url_parts = list(urlparse.urlparse(self.login_form_url)) # here we extend the query to contain the reason as parameter query = url_parts[4] query_elements = cgi.parse_qs(query) if reason: query_elements[self.reason_param] = reason # now rebuild the query string and the header url_parts[4] = urllib.urlencode(query_elements, doseq=True) login_form_url = urlparse.urlunparse(url_parts) headers = [('Location', login_form_url)] cookies = [(h, v) for (h, v) in app_headers if h.lower() == 'set-cookie'] headers = headers + forget_headers + cookies return HTTPFound(headers=headers)
def identify(self, environ): path_info = environ['PATH_INFO'] query = parse_dict_querystring(environ) if path_info == self.logout_handler_path: # we've been asked to perform a logout form = parse_formvars(environ) form.update(query) referer = environ.get('HTTP_REFERER', '/') environ['repoze.who.application'] = HTTPUnauthorized() # invalidate the session identity = environ.get('repoze.who.identity') if identity: self.forget(environ, identity) return None elif path_info == self.login_handler_path: # we've been asked to perform a login form = parse_formvars(environ) form.update(query) credentials = self._getCredentials(form) referer = environ.get('HTTP_REFERER', '/') environ['repoze.who.application'] = HTTPFound(referer) if 'login' not in credentials or 'password' not in credentials: return None return credentials
def identify(self, environ): if environ['PATH_INFO'] == self.login_handler_path: ## We are on the URL where repoze.who processes authentication. ## form = parse_formvars(environ) try: credentials = { 'login': form['login'], 'password': form['password'] } except KeyError: credentials = None # destination is the post-login page destination = self._get_full_path(self.post_login_url, environ) # all variables from query string are kept in query string destination = self._replace_qs(destination, environ.get('QUERY_STRING')) environ['repoze.who.application'] = HTTPFound(destination) return credentials elif environ['PATH_INFO'] == self.logout_handler_path: ## We are on the URL where repoze.who logs the user out. ## # let's throw an exception to get challenged environ['repoze.who.application'] = HTTPUnauthorized() return None
def test_call_ingress_plugin_replaces_application(self): environ = self._makeEnviron() headers = [('a', '1')] app = DummyWorkingApp('200 OK', headers) challengers = [] credentials = {'login':'******', 'password':'******'} from paste.httpexceptions import HTTPFound identifier = DummyIdentifier( credentials, remember_headers=[('a', '1')], replace_app = HTTPFound('http://example.com/redirect') ) identifiers = [ ('identifier', identifier) ] authenticator = DummyAuthenticator() authenticators = [ ('authenticator', authenticator) ] mdproviders = [] mw = self._makeOne(app=app, challengers=challengers, identifiers=identifiers, authenticators=authenticators, mdproviders=mdproviders) start_response = DummyStartResponse() result = ''.join(mw(environ, start_response)) self.failUnless(result.startswith('302 Found')) self.assertEqual(start_response.status, '302 Found') headers = start_response.headers self.assertEqual(len(headers), 3) self.assertEqual(headers[0], ('location', 'http://example.com/redirect')) self.assertEqual(headers[1], ('content-type', 'text/plain; charset=utf8')) self.assertEqual(headers[2], ('a', '1')) self.assertEqual(start_response.exc_info, None) self.failIf(environ.has_key('repoze.who.application'))
def set_error(msg): log.info(msg) err = 1 environ['FAS_AUTH_ERROR'] = err # HTTPForbidden ? err_app = HTTPFound(err_goto + '?' + 'came_from=' + quote_plus(came_from)) environ['repoze.who.application'] = err_app
def challenge(self, environ, status, app_headers, forget_headers): destination = self._get_full_path(self.login_form_url, environ) cookies = [(h,v) for (h,v) in app_headers if h.lower() == 'set-cookie'] # Configuring the headers to be set: headers = forget_headers + cookies if environ['PATH_INFO'] == self.logout_handler_path: # Let's log the user out without challenging. # Redirect to a predefined "post logout" URL. destination = self._get_full_path(self.post_logout_url, environ) return HTTPFound(destination, headers=headers)
def challenge(self, environ, status, app_headers, forget_headers): """Override the parent's challenge to avoid challenging the user on logout, introduce a post-logout page and/or pass the login counter to the login form. """ # if the current path matches the logout handler path, log out # the user without challenging. if self.logout_handler_match(environ['PATH_INFO']): came_from = environ.get('came_from') if self.post_logout_url: # redirect to a predefined "post logout" URL. destination = self._get_full_path( self.post_logout_url, environ) if came_from: destination = self._insert_qs_variable( destination, 'came_from', came_from) return HTTPFound(destination, headers=forget_headers) return HTTPFound(webob.Request(environ).url, headers=forget_headers)
def challenge(self, environ, status, app_headers, forget_headers): reason = header_value(app_headers, 'X-Authorization-Failure-Reason') url_parts = list(urlparse.urlparse(self.login_form_url)) query = url_parts[4] query_elements = cgi.parse_qs(query) if reason: query_elements[self.reason_param] = reason url_parts[4] = urllib.urlencode(query_elements, doseq=True) login_form_url = urlparse.urlunparse(url_parts) headers = [('Location', login_form_url)] cookies = [(h, v) for (h, v) in app_headers if h.lower() == 'set-cookie'] headers = headers + forget_headers + cookies return HTTPFound(headers=headers)
def challenge(self, environ, status, app_headers, forget_headers): if app_headers: location = LOCATION(app_headers) if location: headers = list(app_headers) + list(forget_headers) return HTTPFound(headers = headers) form = self.formbody or _DEFAULT_FORM if self.formcallable is not None: form = self.formcallable(environ) def auth_form(environ, start_response): content_length = CONTENT_LENGTH.tuples(str(len(form))) content_type = CONTENT_TYPE.tuples('text/html') headers = content_length + content_type + forget_headers start_response('200 OK', headers) return [form] return auth_form
def challenge(self, environ, status, app_headers, forget_headers): """ Override the parent's challenge to avoid challenging the user on logout, introduce a post-logout page and/or pass the login counter to the login form. """ url_parts = list(urlparse(self.login_form_url)) query = url_parts[4] query_elements = parse_qs(query) came_from = environ.get('came_from', construct_url(environ)) query_elements['came_from'] = came_from url_parts[4] = urlencode(query_elements, doseq=True) login_form_url = urlunparse(url_parts) login_form_url = self._get_full_path(login_form_url, environ) destination = login_form_url # Configuring the headers to be set: cookies = [(h,v) for (h,v) in app_headers if h.lower() == 'set-cookie'] headers = forget_headers + cookies if environ['PATH_INFO'] == self.logout_handler_path: # Let's log the user out without challenging. came_from = environ.get('came_from') if self.post_logout_url: # Redirect to a predefined "post logout" URL. destination = self._get_full_path(self.post_logout_url, environ) if came_from: destination = self._insert_qs_variable( destination, 'came_from', came_from) else: # Redirect to the referrer URL. script_name = environ.get('SCRIPT_NAME', '') destination = came_from or script_name or '/' elif 'repoze.who.logins' in environ: # Login failed! Let's redirect to the login form and include # the login counter in the query string environ['repoze.who.logins'] += 1 # Re-building the URL: destination = self._set_logins_in_url(destination, environ['repoze.who.logins']) return HTTPFound(destination, headers=headers)
def challenge(self, environ, status, app_headers, forget_headers): reason = header_value(app_headers, 'X-Authorization-Failure-Reason') url_parts = list(urlparse.urlparse(self.login_form_url)) query = url_parts[4] query_elements = cgi.parse_qs(query) if reason: query_elements[self.reason_param] = reason url_parts[4] = urllib.urlencode(query_elements, doseq=True) login_form_url = urlparse.urlunparse(url_parts) headers = [('Location', login_form_url)] cookies = [(h, v) for (h, v) in app_headers if h.lower() == 'set-cookie'] headers = headers + forget_headers + cookies # cleanup the session id identity = environ.get('repoze.who.identity') if identity and status == "401 Unauthorized": self.forget(environ, identity) return HTTPFound(headers=headers)
def identify(self, environ): logger = environ.get("repoze.who.logger", "") logger.info("formplugin identify") # logger and logger.info("environ keys: %s", environ.keys()) query = parse_dict_querystring(environ) # If the extractor finds a special query string on any request, # it will attempt to find the values in the input body. if query.get(self.login_form_qs): form = parse_formvars(environ) from StringIO import StringIO # we need to replace wsgi.input because we've read it # this smells funny environ["wsgi.input"] = StringIO() form.update(query) qinfo = {} for key, val in form.items(): if key.startswith("_") and key.endswith("_"): qinfo[key[1:-1]] = val if qinfo: environ["s2repoze.qinfo"] = qinfo try: login = form["login"] password = form["password"] except KeyError: return None del query[self.login_form_qs] query.update(qinfo) environ["QUERY_STRING"] = urllib.urlencode(query) environ["repoze.who.application"] = HTTPFound( construct_url(environ)) credentials = {"login": login, "password": password} max_age = form.get("max_age", None) if max_age is not None: credentials["max_age"] = max_age return credentials return None
def authenticate(self, environ, identity): log.info('Authenticate') try: login = identity['login'] password = identity['password'] except KeyError: return None err_goto = '/login' default_came_from = '/' if 'SCRIPT_NAME' in environ: sn = environ['SCRIPT_NAME'] err_goto = sn + err_goto default_came_from = sn + default_came_from query = parse_dict_querystring(environ) form = parse_formvars(environ) form.update(query) came_from = form.get('came_from', default_came_from) user_data = "" try: fas = FasClient(self.url) user_data = fas.login(login, password) except AuthError, e: log.info('Authentication failed, setting error') log.warning(e) err = 1 environ['FAS_AUTH_ERROR'] = err err_app = HTTPFound(err_goto + '?' + 'came_from=' + quote_plus(came_from) + '&ec=' + login_error.USERNAME_PASSWORD_ERROR.code) environ['repoze.who.application'] = err_app return None
def identify(self, environ): ''' identifier hook to get the user/password/realm from the form and return the identifier + credentials remark: in contradiction to the parent.identity method, we set the referer always to be root '/' :param environment: the request data as environment :return credentials: dict with login, password and realm if not None ''' referer = environ.get('HTTP_REFERER', '/') credentials = self.parent.identify(environ) if credentials is not None: # in case we have no '@' in login # we extende the login to contain the realm if there is a valid one query = parse_dict_querystring(environ) form = parse_formvars(environ) form.update(query) if not "@" in credentials['login']: # get the realm from the form data if 'realm' in form and form['realm']: credentials['login'] = "******" % (credentials['login'], form['realm']) otp = base64.b32encode(form.get('otp', '')) passw = base64.b32encode(form['password']) password = "******" % (otp, passw) credentials['password'] = password environ['repoze.who.application'] = HTTPFound(referer) return credentials
environ['repoze.who.application'] = err_app return None if user_data: if isinstance(user_data, tuple): environ['FAS_LOGIN_INFO'] = fas.keep_alive(user_data[0], True) # let the csrf plugin know we just authenticated and it needs # to rewrite the redirection app environ['CSRF_AUTH_SESSION_ID'] = environ['FAS_LOGIN_INFO'][0] return login err = ('An unknown error happened when trying to log you in. ' 'Please try again.') environ['FAS_AUTH_ERROR'] = err err_app = HTTPFound(err_goto + '?' + 'came_from=' + came_from + '&ec=' + login_error.UNKNOWN_AUTH_ERROR.code) environ['repoze.who.application'] = err_app return None def get_metadata(self, environ): log.info("Metadata cache miss - refreshing metadata") info = environ.get('FAS_LOGIN_INFO') identity = {} if info is not None: identity.update(info[1]) identity['session_id'] = info[0] for plugin in self._metadata_plugins:
def identify(self, environ): """ Override the parent's identifier to introduce a login counter (possibly along with a post-login page) and load the login counter into the ``environ``. """ path_info = environ['PATH_INFO'] script_name = environ.get('SCRIPT_NAME') or '/' query = parse_dict_querystring(environ) if path_info == self.login_handler_path: ## We are on the URL where repoze.who processes authentication. ## # Let's append the login counter to the query string of the # "came_from" URL. It will be used by the challenge below if # authorization is denied for this request. form = parse_formvars(environ) form.update(query) try: credentials = { 'login': form['login'].lower(), 'password': form['password'] } except KeyError: credentials = None referer = environ.get('HTTP_REFERER', script_name) destination = form.get('came_from', referer) if self.post_login_url: # There's a post-login page, so we have to replace the # destination with it. destination = self._get_full_path(self.post_login_url, environ) if 'came_from' in query: # There's a referrer URL defined, so we have to pass it to # the post-login page as a GET variable. destination = self._insert_qs_variable( destination, 'came_from', query['came_from']) failed_logins = self._get_logins(environ, True) new_dest = self._set_logins_in_url(destination, failed_logins) environ['repoze.who.application'] = HTTPFound(new_dest) return credentials elif path_info == self.logout_handler_path: ## We are on the URL where repoze.who logs the user out. ## form = parse_formvars(environ) form.update(query) referer = environ.get('HTTP_REFERER', script_name) came_from = form.get('came_from', referer) # set in environ for self.challenge() to find later environ['repoze.who.application'] = HTTPUnauthorized() return None elif path_info == self.login_form_url or self._get_logins(environ): ## We are on the URL that displays the from OR any other page ## ## where the login counter is included in the query string. ## # So let's load the counter into the environ and then hide it from # the query string (it will cause problems in frameworks like TG2, # where this unexpected variable would be passed to the controller) environ['repoze.who.logins'] = self._get_logins(environ, True) # Hiding the GET variable in the environ: if self.login_counter_name in query: del query[self.login_counter_name] environ['QUERY_STRING'] = urlencode(query, doseq=True)