def extractCredentials(self, request, overrides=None): """Extracts credentials from a session if they exist.""" if not IHTTPRequest.providedBy(request): return None session = ISession(request) sessionData = session.get('zope.app.authentication.browserplugins') (login, password, domain, ip) = (None, None, None, None) credentials = None logging_in = False if overrides: login = overrides.get('login', None) password = overrides.get('password', None) ip = overrides.get('ip', None) domain = overrides.get('domain', None) login = login or request.get(self.loginfield, None) password = password or request.get(self.passwordfield, None) domain = domain or request.get(self.domainfield, None) ip = ip or request.environment.get('HTTP_X_FORWARDED_FOR', None) ip = ip or request.environment.get('REMOTE_ADDR', None) if login and password: credentials = SessionCredentials( login, password, ip=ip, domain=domain, request_annotations=request.annotations, passwordManager=self.passwordManager) if IHTTPRequest.providedBy(request): self._update_cookie(request, credentials) logging_in = True elif not sessionData: return None sessionData = session['zope.app.authentication.browserplugins'] if credentials: sessionData['credentials'] = credentials else: credentials = sessionData.get('credentials', None) if not credentials: return None if credentials.isExpired(self.idleExpiry): return None return { 'login': credentials.getLogin(), 'password': credentials.getPassword(), 'ip': credentials.getIP(), 'domain': credentials.getDomain(), 'logging_in': logging_in, 'request-annotations': credentials.getRequestAnnotations(), 'extractTime': credentials.getExtractTime(), 'accessTime': credentials.getAccessTime(), 'passwordManager': credentials.getPasswordManager(), }
def logout(self, request): if not IHTTPRequest.providedBy(request): return request.response.expireCookie(self.cookie_name, path="/") session = ISession(request, None) if session is not None: session.delete()
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return None login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) session = ISession(request) sessionData = session.get('zope.pluggableauth.browserplugins') traversalStack = request.getTraversalStack() authMethod = 'standard' credentials = None if sessionData: credentials = sessionData.get('credentials') if isinstance(sessionData, TwoFactorSessionCredentials): authMethod = '2factor' if (authMethod == 'standard' and traversalStack and traversalStack[-1].startswith('++auth++')): authMethod = traversalStack[-1][8:] viewAnnotations = request.annotations.setdefault('loops.view', {}) viewAnnotations['auth_method'] = authMethod #log.info('authentication method: %s.' % authMethod) if authMethod == 'standard': return self.extractStandardCredentials( request, login, password, session, credentials) elif authMethod == '2factor': return self.extract2FactorCredentials( request, login, password, session, credentials) else: return None
def get_request_language(): request = common.get_request() if IHTTPRequest.providedBy(request): lang = request.locale.getLocaleID() else: lang = capi.default_language return lang
def extractCredentials(self, request): """Extracts credentials from a session if they exist.""" if not IHTTPRequest.providedBy(request): return None session = ISession(request, None) sessionData = session.get('z3c.authenticator.credential.session') login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) # support z3c.form prefixes for prefix in self.prefixes: login = request.get(prefix + self.loginfield, login) password = request.get(prefix + self.passwordfield, password) credentials = None if login and password: credentials = SessionCredentials(login, password) elif not sessionData: return None sessionData = session['z3c.authenticator.credential.session'] if credentials: sessionData['credentials'] = credentials else: credentials = sessionData.get('credentials', None) if not credentials: return None return {'login': credentials.getLogin(), 'password': credentials.getPassword()}
def extractCredentials(self, request): if not IHTTPRequest.providedBy( request ): return None login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) cookie = request.get(self.cookie_name, None) # login attempt if login and password: # verify the credentials and then setup token, needs a double login for # initial login attempts creds = {'login': login, 'password':password } # does assume a pluggable authentication utility for auth_name, auth in getUtility( IAuthentication ).getAuthenticatorPlugins(): if auth.authenticateCredentials( creds ): self.setupTokenSession( login, request ) break return creds # check for token if not self.cookie_name in request: return None # extract token try: return { 'token': binascii.a2b_base64(request.get(self.cookie_name)) } except binascii.Error: # If we have a cookie which is not properly base64 encoded it # can not be ours. return None
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return None login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) session = ISession(request) sessionData = session.get('zope.pluggableauth.browserplugins') traversalStack = request.getTraversalStack() authMethod = 'standard' credentials = None if sessionData: credentials = sessionData.get('credentials') if isinstance(sessionData, TwoFactorSessionCredentials): authMethod = '2factor' if (authMethod == 'standard' and traversalStack and traversalStack[-1].startswith('++auth++')): authMethod = traversalStack[-1][8:] viewAnnotations = request.annotations.setdefault('loops.view', {}) viewAnnotations['auth_method'] = authMethod #log.info('authentication method: %s.' % authMethod) if authMethod == 'standard': return self.extractStandardCredentials(request, login, password, session, credentials) elif authMethod == '2factor': return self.extract2FactorCredentials(request, login, password, session, credentials) else: return None
def getLanguage(self): try: request = get_request() if request and IHTTPRequest.providedBy(request): return request.getCookies().get(I18N_COOKIE_NAME) except zope.security.interfaces.NoInteraction: return None
def extractCredentials(self, request): """Extracts credentials from a session if they exist.""" if not IHTTPRequest.providedBy(request): return None session = ISession(request) sessionData = session.get( 'zope.pluggableauth.browserplugins') login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) credentials = None if login and password: credentials = self._makeCredentials(login, password) elif not sessionData: return None sessionData = session[ 'zope.pluggableauth.browserplugins'] if credentials: sessionData['credentials'] = credentials else: credentials = sessionData.get('credentials', None) if not credentials: return None return {'login': credentials.getLogin(), 'password': credentials.getPassword()}
def solrSearchResults(request=None, **keywords): """ perform a query using solr after translating the passed in parameters with portal catalog semantics """ site = getSite() search = queryUtility(ISearch, context=site) config = queryUtility(ISolrConnectionConfig, context=site) if request is None: # try to get a request instance, so that flares can be adapted to # ploneflares and urls can be converted into absolute ones etc; # however, in this case any arguments from the request are ignored args = deepcopy(keywords) request = getattr(site, 'REQUEST', None) elif IHTTPRequest.providedBy(request): args = deepcopy(request.form) args.update(keywords) # keywords take precedence else: assert isinstance(request, dict), request args = deepcopy(request) args.update(keywords) # keywords take precedence # if request is a dict, we need the real request in order to # be able to adapt to plone flares request = getattr(site, 'REQUEST', args) if 'path' in args and 'navtree' in args['path']: raise FallBackException # we can't handle navtree queries yet use_solr = args.get('use_solr', False) # A special key to force Solr if not use_solr and config.required: required = set(config.required).intersection(args) if required: for key in required: if not args[key]: raise FallBackException else: raise FallBackException query, params = search.buildQueryAndParameters(**args) if query != {}: __traceback_info__ = (query, params, args) response = search(query, **params) else: return SolrResponse() def wrap(flare): """ wrap a flare object with a helper class """ adapter = queryMultiAdapter((flare, request), IFlare) return adapter is not None and adapter or flare schema = search.getManager().getSchema() or {} results = response.results() for idx, flare in enumerate(results): flare = wrap(flare) for missing in set(schema.stored).difference(flare): flare[missing] = MV results[idx] = wrap(flare) padResults(results, **params) # pad the batch return response
def extractCredentials(self, request): """Extracts HTTP basic auth credentials from a request. First we need to create a request that contains some credentials. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest( ... environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'}) Now create the plugin and get the credentials. >>> plugin = HTTPBasicAuthCredentialsPlugin() >>> from pprint import pprint >>> pprint(plugin.extractCredentials(request)) {'login': u'mgr', 'password': u'mgrpw'} Make sure we return `None`, if no authentication header has been specified. >>> print(plugin.extractCredentials(TestRequest())) None Also, this plugin can *only* handle basic authentication. >>> request = TestRequest(environ={'HTTP_AUTHORIZATION': 'foo bar'}) >>> print(plugin.extractCredentials(TestRequest())) None This plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> print(plugin.extractCredentials(TestRequest('/'))) None According to RFC 2617, password can contain one or more colons; user ID can't contain any colon. >>> from zope.publisher.browser import TestRequest as BrowserRequest >>> request = BrowserRequest('/', ... environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3OndpdGg6Y29sb24='}) >>> pprint(plugin.extractCredentials(request)) {'login': u'mgr', 'password': u'mgrpw:with:colon'} """ if not IHTTPRequest.providedBy(request): return None if request._auth: if request._auth.lower().startswith(u'basic '): credentials = request._auth.split()[-1] if isinstance(credentials, unicode): # No encoding needed, should be base64 string anyways. credentials = credentials.encode() login, password = base64.b64decode(credentials).split(b':', 1) return {'login': login.decode('utf-8'), 'password': password.decode('utf-8')} return None
def logout(self, request): """Performs logout by clearing session data credentials.""" if not IHTTPRequest.providedBy(request): return False sessionData = ISession(request)['z3c.authenticator.credential.session'] sessionData['credentials'] = None sessionData['camefrom'] = None transaction.commit() return True
def logout(self, request): """Performs logout by clearing session data credentials.""" if not IHTTPRequest.providedBy(request): return False sessionData = ISession( request)['zope.app.authentication.browserplugins'] sessionData['credentials'] = None transaction.commit() return True
def logout(self, request): """Performs logout by clearing session data credentials.""" if not IHTTPRequest.providedBy(request): return False sessionData = ISession(request)[ 'zope.app.authentication.browserplugins'] sessionData['credentials'] = None transaction.commit() return True
def solrSearchResults(request=None, **keywords): """ perform a query using solr after translating the passed in parameters with portal catalog semantics """ search = queryUtility(ISearch) config = queryUtility(ISolrConnectionConfig) if request is None: # try to get a request instance, so that flares can be adapted to # ploneflares and urls can be converted into absolute ones etc; # however, in this case any arguments from the request are ignored request = getattr(getSiteManager(), "REQUEST", None) args = keywords elif IHTTPRequest.providedBy(request): args = request.form.copy() # ignore headers and other stuff args.update(keywords) # keywords take precedence else: assert isinstance(request, dict), request args = request.copy() args.update(keywords) # keywords take precedence # if request is a dict, we need the real request in order to # be able to adapt to plone flares request = getattr(getSiteManager(), "REQUEST", args) if "path" in args and "navtree" in args["path"]: raise FallBackException # we can't handle navtree queries yet use_solr = args.get("use_solr", False) # A special key to force Solr if not use_solr and config.required: required = set(config.required).intersection(args) if required: for key in required: if not args[key]: raise FallBackException else: raise FallBackException schema = search.getManager().getSchema() or {} params = cleanupQueryParameters(extractQueryParameters(args), schema) languageFilter(args) prepareData(args) mangleQuery(args, config, schema) query = search.buildQuery(**args) optimizeQueryParameters(query, params) __traceback_info__ = (query, params, args) response = search(query, fl="* score", **params) def wrap(flare): """ wrap a flare object with a helper class """ adapter = queryMultiAdapter((flare, request), IFlare) return adapter is not None and adapter or flare results = response.results() for idx, flare in enumerate(results): flare = wrap(flare) for missing in set(schema.stored).difference(flare): flare[missing] = MV results[idx] = wrap(flare) # padResults(results, **params) # pad the batch return response
def get_request_language(request=None, default=capi.default_language): """Get current request's language; if no request use specified default. If the request instance is handy, it may be passed in as a parameter thus avoidng the need to call for it. """ if request is None: request = common.get_request() if IHTTPRequest.providedBy(request): return request.locale.getLocaleID() return default
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return None # this is an access token in the URL ?access_token=... if not hasattr(request, 'form'): return None access_token = (request.form.get('access_token', None) or request.form.get('form.field.access_token', None)) if access_token is not None: return {'access_token': access_token} return None
def challenge(self, request): if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() path = request['PATH_INFO'].split('/++/')[ -1] # strip virtual host stuff if not path.startswith('/'): path = '/' + path camefrom = request.getApplicationURL() + path if 'login' in camefrom: camefrom = '/'.join(camefrom.split('/')[:-1]) url = '%s/@@%s?%s' % (absoluteURL(site, request), self.loginpagename, urlencode({'camefrom': camefrom})) request.response.redirect(url) return True
def challenge(self, request): if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() path = request['PATH_INFO'].split('/++/')[-1] # strip virtual host stuff if not path.startswith('/'): path = '/' + path camefrom = request.getApplicationURL() + path if 'login' in camefrom: camefrom = '/'.join(camefrom.split('/')[:-1]) url = '%s/@@%s?%s' % (absoluteURL(site, request), self.loginpagename, urlencode({'camefrom': camefrom})) request.response.redirect(url) return True
def extractCredentials(self, request): """Extracts HTTP basic auth credentials from a request. First we need to create a request that contains some credentials. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest( ... environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'}) Now create the plugin and get the credentials. >>> plugin = HTTPBasicAuthCredentialsPlugin() >>> plugin.extractCredentials(request) {'login': u'mgr', 'password': u'mgrpw'} Make sure we return `None`, if no authentication header has been specified. >>> print plugin.extractCredentials(TestRequest()) None Also, this plugin can *only* handle basic authentication. >>> request = TestRequest(environ={'HTTP_AUTHORIZATION': 'foo bar'}) >>> print plugin.extractCredentials(TestRequest()) None This plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> print plugin.extractCredentials(TestRequest('/')) None """ if not IHTTPRequest.providedBy(request): return None if request._auth: if request._auth.lower().startswith(u'basic '): credentials = request._auth.split()[-1] login, password = base64.decodestring(credentials).split(':') return { 'login': login.decode('utf-8'), 'password': password.decode('utf-8') } return None
def extractCredentials(self, request): """Extracts HTTP basic auth credentials from a request. First we need to create a request that contains some credentials. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest( ... environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'}) Now create the plugin and get the credentials. >>> plugin = HTTPBasicAuthCredentialsPlugin() >>> sorted(plugin.extractCredentials(request).items()) [('login', 'mgr'), ('password', 'mgrpw')] Make sure we return `None`, if no authentication header has been specified. >>> print(plugin.extractCredentials(TestRequest())) None Also, this plugin can *only* handle basic authentication. >>> request = TestRequest(environ={'HTTP_AUTHORIZATION': 'foo bar'}) >>> print(plugin.extractCredentials(TestRequest())) None This plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> print(plugin.extractCredentials(TestRequest('/'))) None """ if not IHTTPRequest.providedBy(request): return None if request._auth: if request._auth.lower().startswith(u'basic '): credentials = request._auth.split()[-1] if isinstance(credentials, six.text_type): credentials = credentials.encode('utf-8') login, password = base64.decodestring(credentials).split(b':') return {'login': login.decode('utf-8'), 'password': password.decode('utf-8')} return None
def extractCredentials(self, request): """Extracts credentials from a session if they exist.""" if not IHTTPRequest.providedBy(request): return None sessionData = ISession(request)[ 'zope.app.authentication.browserplugins'] login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) if login and password: credentials = SessionCredentials(login, password) sessionData['credentials'] = credentials credentials = sessionData.get('credentials', None) if not credentials: return None return {'login': credentials.getLogin(), 'password': credentials.getPassword()}
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) gebdate = request.get(self.gebdatefield, None) cookie = request.get(self.cookie_name, None) if login and password and gebdate: cookie = self.make_cookie(login, password, gebdate) request.response.setCookie(self.cookie_name, cookie, path="/") elif cookie: val = base64.decodestring(urllib.unquote(cookie)).decode("utf-8") login, password, gebdate = val.split(":") else: return return {"login": login, "password": password, "gebdate": gebdate}
def extractCredentials(self, request): """Extracts HTTP basic auth credentisla from a request. First we need to create a request that contains some credentials. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest( ... environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'}) Now create the plugin and get the credentials. >>> plugin = HTTPBasicAuthCredentialsPlugin() >>> plugin.extractCredentials(request) {'login': u'mgr', 'password': u'mgrpw'} Make sure we return `None`, if no authentication header has been specified. >>> print plugin.extractCredentials(TestRequest()) None Also, this plugin can *only* handle basic authentication. >>> request = TestRequest(environ={'HTTP_AUTHORIZATION': 'foo bar'}) >>> print plugin.extractCredentials(TestRequest()) None This plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> print plugin.extractCredentials(TestRequest('/')) None """ if not IHTTPRequest.providedBy(request): return None if request._auth: if request._auth.lower().startswith(u"basic "): credentials = request._auth.split()[-1] login, password = base64.decodestring(credentials).split(":") return {"login": login.decode("utf-8"), "password": password.decode("utf-8")} return None
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) cookie = request.get(self.cookie_name, None) if login and password: val = base64.encodestring('%s:%s' % (login, password)) request.response.setCookie(self.cookie_name, urllib.quote(val), path='/') elif cookie: val = base64.decodestring(urllib.unquote(cookie)) login, password = val.split(':') else: return return {'login': login, 'password': password}
def challenge(self, request): """Issues an HTTP basic auth challenge for credentials. The challenge is issued by setting the appropriate response headers. To illustrate, we'll create a plugin: >>> plugin = HTTPBasicAuthCredentialsPlugin() The plugin adds its challenge to the HTTP response. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() >>> response = request.response >>> plugin.challenge(request) True >>> response._status 401 >>> response.getHeader('WWW-Authenticate', literal=True) 'basic realm="Zope"' Notice that the realm is quoted, as per RFC 2617. The plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> request = TestRequest('/') >>> response = request.response >>> print(plugin.challenge(request)) False """ if not IHTTPRequest.providedBy(request): return False request.response.setHeader("WWW-Authenticate", 'basic realm="%s"' % self.realm, literal=True) request.response.setStatus(401) return True
def challenge(self, request): """Issues an HTTP basic auth challenge for credentials. The challenge is issued by setting the appropriate response headers. To illustrate, we'll create a plugin: >>> plugin = HTTPBasicAuthCredentialsPlugin() The plugin adds its challenge to the HTTP response. >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() >>> response = request.response >>> plugin.challenge(request) True >>> response._status 401 >>> response.getHeader('WWW-Authenticate', literal=True) 'basic realm="Zope"' Notice that the realm is quoted, as per RFC 2617. The plugin only works with HTTP requests. >>> from zope.publisher.base import TestRequest >>> request = TestRequest('/') >>> response = request.response >>> print plugin.challenge(request) False """ if not IHTTPRequest.providedBy(request): return False request.response.setHeader("WWW-Authenticate", 'basic realm="%s"' % self.realm, literal=True) request.response.setStatus(401) return True
def extractCredentials(self, request): if not IHTTPRequest.providedBy(request): return login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) cookie = request.get(self.cookie_name, None) if login and password: login = login.encode('utf-8') password = password.encode('utf-8') cookie = self.make_cookie(login, password) request.response.setCookie(self.cookie_name, cookie, path="/") elif cookie: val = base64.decodebytes( urllib.parse.unquote(cookie).encode("utf-8")) login, password = val.split(b":") else: return return { "login": login.decode('utf-8'), "password": password.decode('utf-8') }
def challenge(self, request): """Challenges by redirecting to a login form. To illustrate, we'll create a test request: >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() and confirm its response's initial status and 'location' header: >>> request.response.getStatus() 599 >>> request.response.getHeader('location') When we issue a challenge using a session plugin: >>> plugin = SessionCredentialsPlugin() >>> plugin.challenge(request) True we get a redirect: >>> request.response.getStatus() 302 >>> request.response.getHeader('location') 'http://127.0.0.1/@@loginForm.html?camefrom=%2F' The plugin redirects to the page defined by the loginpagename attribute: >>> plugin.loginpagename = 'mylogin.html' >>> plugin.challenge(request) True >>> request.response.getHeader('location') 'http://127.0.0.1/@@mylogin.html?camefrom=%2F' It also provides the request URL as a 'camefrom' GET style parameter. To illustrate, we'll pretend we've traversed a couple names: >>> env = { ... 'REQUEST_URI': '/foo/bar/folder/page%201.html?q=value', ... 'QUERY_STRING': 'q=value' ... } >>> request = TestRequest(environ=env) >>> request._traversed_names = [u'foo', u'bar'] >>> request._traversal_stack = [u'page 1.html', u'folder'] >>> request['REQUEST_URI'] '/foo/bar/folder/page%201.html?q=value' When we challenge: >>> plugin.challenge(request) True We see the 'camefrom' points to the requested URL: >>> request.response.getHeader('location') # doctest: +ELLIPSIS '.../@@mylogin.html?camefrom=%2Ffoo%2Fbar%2Ffolder%2Fpage+1.html%3Fq%3Dvalue' This can be used by the login form to redirect the user back to the originating URL upon successful authentication. """ if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() # We need the traversal stack to complete the 'camefrom' parameter stack = request.getTraversalStack() stack.reverse() # Better to add the query string, if present query = request.get('QUERY_STRING') camefrom = '/'.join([request.getURL(path_only=True)] + stack) if query: camefrom = camefrom + '?' + query url = '%s/@@%s?%s' % (absoluteURL(site, request), self.loginpagename, urlencode({'camefrom': camefrom})) request.response.redirect(url) return True
def challenge(self, request): """Challenges by redirecting to a loging form. To illustrate, we'll create a test request: >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() and confirm its response's initial status and 'location' header: >>> request.response.getStatus() 599 >>> request.response.getHeader('location') When we issue a challenge using a session plugin: >>> plugin = SessionCredentialsPlugin() >>> plugin.challenge(request) True we get a redirect: >>> request.response.getStatus() 302 >>> request.response.getHeader('location') 'http://127.0.0.1/@@loginForm.html?camefrom=http%3A%2F%2F127.0.0.1' The plugin redirects to the page defined by the loginpagename attribute: >>> plugin.loginpagename = 'mylogin.html' >>> plugin.challenge(request) True >>> request.response.getHeader('location') 'http://127.0.0.1/@@mylogin.html?camefrom=http%3A%2F%2F127.0.0.1' It also provides the request URL as a 'camefrom' GET style parameter. To illustrate, we'll pretend we've traversed a couple names: >>> request._traversed_names = ['foo', 'bar'] >>> request.getURL() 'http://127.0.0.1/foo/bar' When we challenge: >>> plugin.challenge(request) True We see the 'camefrom' points to the traversed URL: >>> request.response.getHeader('location') # doctest: +ELLIPSIS '.../@@mylogin.html?camefrom=http%3A%2F%2F127.0.0.1%2Ffoo%2Fbar' This can be used by the login form to redirect the user back to the originating URL upon successful authentication. """ if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() camefrom = request.getURL() url = '%s/@@%s?%s' % (absoluteURL(site, request), self.loginpagename, urlencode({'camefrom': camefrom})) request.response.redirect(url) return True
def challenge(self, request): """Challenges by redirecting to a login form. To illustrate, we'll create a test request: >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() and confirm its response's initial status and 'location' header: >>> request.response.getStatus() 599 >>> request.response.getHeader('location') When we issue a challenge using a session plugin: >>> plugin = SessionCredentialsPlugin() >>> plugin.challenge(request) True we get a redirect: >>> request.response.getStatus() 302 >>> request.response.getHeader('location') 'http://127.0.0.1/@@loginForm.html?camefrom=http%3A%2F%2F127.0.0.1' The plugin redirects to the page defined by the loginpagename attribute: >>> plugin.loginpagename = 'mylogin.html' >>> plugin.challenge(request) True >>> request.response.getHeader('location') 'http://127.0.0.1/@@mylogin.html?camefrom=http%3A%2F%2F127.0.0.1' It also provides the request URL as a 'camefrom' GET style parameter. To illustrate, we'll pretend we've traversed a couple names: >>> env = { ... 'REQUEST_URI': '/foo/bar/folder/page%201.html?q=value', ... 'QUERY_STRING': 'q=value' ... } >>> request = TestRequest(environ=env) >>> request._traversed_names = [u'foo', u'bar'] >>> request._traversal_stack = [u'page 1.html', u'folder'] >>> request['REQUEST_URI'] '/foo/bar/folder/page%201.html?q=value' When we challenge: >>> plugin.challenge(request) True We see the 'camefrom' points to the requested URL: >>> request.response.getHeader('location') 'http://127.0.0.1/@@mylogin.html?camefrom=http%3A%2F%2F127.0.0.1%2Ffoo%2Fbar%2Ffolder%2Fpage+1.html%3Fq%3Dvalue' This can be used by the login form to redirect the user back to the originating URL upon successful authentication. Now that the 'camefrom' is an absolute URL, quickly demonstrate that 'camefrom' information that inadvertently points to a different host, will by default not be trusted in a redirect: >>> camefrom = request.response.getHeader('location') >>> request.response.redirect(camefrom) 'http://127.0.0.1/@@mylogin.html?camefrom=http%3A%2F%2F127.0.0.1%2Ffoo%2Fbar%2Ffolder%2Fpage+1.html%3Fq%3Dvalue' >>> suspicious_camefrom = 'http://example.com/foobar' >>> request.response.redirect(suspicious_camefrom) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Untrusted redirect to host 'example.com:80' not allowed. """ if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() redirectWithComeFrom(request, '%s/@@%s' % (absoluteURL(site, request), self.loginpagename)) return True
def logout(self, request): if not IHTTPRequest.providedBy(request): return request.response.expireCookie(self.cookie_name, path=self.cookie_path )
def extractCredentials(self, request): # noqa """Extracts credentials from a session if they exist.""" if not IHTTPRequest.providedBy(request): return None session = ISession(request) # Fun. Direct access created a default. .get doesn't session_data = session['zope.pluggableauth.browserplugins'] login = request.get(self.loginfield, None) password = request.get(self.passwordfield, None) tan_a = request.get(self.tan_a_field, None) tan_b = request.get(self.tan_b_field, None) hash = request.get(self.hash_field, None) credentials = None redirect = request.response.redirect def _validate_tans(a, b, creds): tan = str(creds.tan) if tan[creds.tanA] == a and \ tan[creds.tanB] == b: return True return False def _validate_captcha(): return submit(request['recaptcha_challenge_field'], request['recaptcha_response_field'], PRIVKEY, '') # netifaces.ifaddresses('eth0')[2][0]['addr'] if login and password and not tan_a and not tan_b and not hash: # 1st phase, user has provided login and password log.info('First Phase: Got login and password, no TANs.') credentials = TwoFactorSessionCredentials(login, password) session_data['credentials'] = credentials # Send email to user self.send_tan_email(login, credentials.tan) log.info("Thank you for logging in. Then Tan is %s. " % credentials.tan) url = '%s/@@tanForm.html?h=%s&a=%s&b=%s' % \ (request.getURL(), credentials.hash, credentials.tanA + 1, credentials.tanB + 1) if request.get('camefrom'): url += "&camefrom=%s" % request['camefrom'] redirect(url) elif not login and not password and hash: # 2nd phase, user has given TANs and the hash. log.info('2nd Phase. No login or password, but TANs.') credentials = session_data.get('credentials', None) if not (tan_a and tan_b): msg = u"There was a problem reading your TAN digits. " + \ u"Please try again." log.info(msg) return redirect('@@tanForm.html?e=%s&hash=%s&a=%s&b=%s' % (msg, hash, credentials.tanA + 1, credentials.tanB + 1)) # Validate the captcha r = _validate_captcha() if not r.is_valid: msg = u"The captcha did not validate. Please try again." log.info(msg) return redirect( '@@tanForm.html?e=%s&h=%s&a=%s&b=%s&tan_a=%s&tan_b=%s' % (msg, hash, credentials.tanA + 1, credentials.tanB + 1, tan_a, tan_b)) log.info('The captcha is valid, continuing...') # No credentials, fail if not credentials: msg = u"We couldn't find your credentials. Please try again." log.info(msg) return redirect('@@loginForm.html?e=%s' % (msg)) # No or wrong hash provided, fail if credentials.hash != hash: msg = u"Somehow this page doesn't fit to the previous one." + \ u"Please start from scratch." log.info(msg) return redirect('@@loginForm.html?e=%s' % (msg)) # Took longer than TIMEOUT, fail if credentials.timestamp < datetime.now() - TIMEOUT: msg = u"A timeout has been reached. " + \ u"Please start from scratch." log.info(msg) return redirect('@@loginForm.html?e=%s' % (msg)) # Can't validate tans, fail if not _validate_tans(tan_a, tan_b, credentials): msg = u"The provided TAN digits don't fit. Please try again." log.info(msg) return redirect('@@tanForm.html?e=%s&a=%s&b=%s' % (msg, credentials.tanA + 1, credentials.tanB + 1)) credentials.validated = True log.info('Credentials are valid') session_data['credentials'] = credentials if request.get('camefrom'): redirect(request.get('camefrom')) else: redirect('./@@contents.html') elif not session_data: # Just display loginForm.html return None session_data = session['zope.pluggableauth.browserplugins'] credentials = session_data.get('credentials', None) if not credentials: log.info('credentials are None') return None if not credentials.validated: log.warn("User is not validated. Don't log in!") return None log.info("All fine, user can be logged in, return credentials.") return {'login': credentials.getLogin(), 'password': credentials.getPassword()}
def challenge(self, request): """Challenges by redirecting to a login form. To illustrate how a session plugin works, we'll first setup some session machinery: >>> from z3c.authenticator.testing import sessionSetUp >>> sessionSetUp() and we'll create a test request: >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() and confirm its response's initial status and 'location' header: >>> request.response.getStatus() 599 >>> request.response.getHeader('location') When we issue a challenge using a session plugin: >>> plugin = SessionCredentialsPlugin() >>> plugin.challenge(request) True we get a redirect: >>> request.response.getStatus() 302 >>> request.response.getHeader('location') 'http://127.0.0.1/@@loginForm.html' and the camefrom session contains the camefrom url which is our application root by default: >>> session = ISession(request, None) >>> sessionData = session['z3c.authenticator.credential.session'] >>> sessionData['camefrom'] '/' The plugin redirects to the page defined by the loginpagename attribute: >>> plugin.loginpagename = 'mylogin.html' >>> plugin.challenge(request) True >>> request.response.getHeader('location') 'http://127.0.0.1/@@mylogin.html' and the camefrom session contains the camefrom url which is our application root by default: >>> session = ISession(request, None) >>> sessionData = session['z3c.authenticator.credential.session'] >>> sessionData['camefrom'] '/' It also provides the request URL as a 'camefrom' GET style parameter. To illustrate, we'll pretend we've traversed a couple names: >>> env = { ... 'REQUEST_URI': '/foo/bar/folder/page%201.html?q=value', ... 'QUERY_STRING': 'q=value' ... } >>> request = TestRequest(environ=env) >>> request._traversed_names = [u'foo', u'bar'] >>> request._traversal_stack = [u'page 1.html', u'folder'] >>> request['REQUEST_URI'] '/foo/bar/folder/page%201.html?q=value' When we challenge: >>> plugin.challenge(request) True We see the url points to the login form URL: >>> request.response.getHeader('location') # doctest: +ELLIPSIS 'http://127.0.0.1/@@mylogin.html' and the camefrom session contains the camefrom url: >>> session = ISession(request, None) >>> sessionData = session['z3c.authenticator.credential.session'] >>> sessionData['camefrom'] u'/foo/bar/folder/page%201.html?q=value' If the given challenge argument doesn't provide IHTTPRequest the result will always be False: >>> plugin.challenge(None) False This can be used by the login form to redirect the user back to the originating URL upon successful authentication. """ if not IHTTPRequest.providedBy(request): return False site = hooks.getSite() # We need the traversal stack to complete the 'camefrom' parameter stack = request.getTraversalStack() stack.reverse() # Better to add the query string, if present query = request.get('QUERY_STRING') camefrom = '/'.join([request.getURL(path_only=True)] + stack) if query: camefrom = camefrom + '?' + query url = '%s/@@%s' % (absoluteURL(site, request), self.loginpagename) # only redirect to the login form request.response.redirect(url) # and store the camefrom url into a session variable, then this url # should not get exposed in the login form url. session = ISession(request, None) sessionData = session['z3c.authenticator.credential.session'] # XXX: this might be problematic with non-ASCII html page names sessionData['camefrom'] = camefrom.replace(' ', '%20') return True