def _process_contact(self): # Validate secure_form's (CSRF protection) token if not (request.params.get(secure_form.token_key) == secure_form.authentication_token()): abort (403, detail=u'Not permitted (possible CSRF attack)') # If cancelled, dont do anything if request.params.get('op') != 'Submit': session.pop('contactform.errors', None) session.pop('contactform.values', None) return url(controller='contactform', action='nevermind') # Validate form fields ... schema = ContactForm() try: fields = schema.to_python(dict(request.params)) session.pop('contactform.errors', None) session.pop('contactform.values', None) self._save_contact(fields, schema) return url(controller='contactform', action='thanks') except formencode.Invalid, ex: session.update({ 'contactform.errors': ex.error_dict, 'contactform.values': ex.value, }) return url(controller='contactform', action='contact')
def _vote_save(self): post = request.POST # Fetch POST data vote = post.get(u'vote') email = post.get(u'email') op = post.get(u'op') attachment = post.get(u'vote-attachment') comment = post.get(u'vote-comment') fp = attachment.file if isinstance(attachment, cgi.FieldStorage) else None attachment_data = fp.read(256).decode('utf-8') if fp else '<None>' # Note: assume plain text utf-8 file #raise Exception('Inspect POST data') # Validate request if not (post.get(secure_form.token_key, None) == secure_form.authentication_token()): abort (403, detail=u'Not permitted (possible CSRF attack)') # Validate POST data: in practice we should not abort but rather redirect to the form # with all the errors highlighted vote = int(vote) if not (vote >= 0 and vote <= 10): abort (400, detail=u'Bad value for vote') # Done with validation, now just log this and store the (vote,email) in the underlying model log.info ('Saving vote for poll (%r)' %(dict(vote=vote, email=email, op=op, attachment_data=attachment_data))) db_session = model.Session() v = model.Vote (vote=vote, email=email, created_at=None, description=comment); db_session.add(v) db_session.commit() # Done with form processing, redirect to a normal (GET) request ... h.flash('Your vote is saved!') redirect (url(controller='poll', action='results')) return
def __call__(self, environ, start_response): """Invoke the Controller""" # WSGIController.__call__ dispatches to the Controller method # the request is routed to. This routing information is # available in environ['pylons.routes_dict'] environ = request.environ controller = environ['pylons.routes_dict'].get('controller') if request.method == "POST" and controller != "auth" and controller != "hookbox" and controller != 'error': params = request.params submitted_token = params.get(secure_form.token_key) if submitted_token != secure_form.authentication_token(): #raise RuntimeError("Not secure") pass #FIXME: uncomment above user_id = session.get("user_id") if user_id: c.user = self.user = User.get(user_id) if not self.user.is_logged_in(): del session["user_id"] c.user = self.user = None else: c.user = self.user = None #generate hookbox server url hookbox_server = url('/', qualified=True) parsed = urlparse(hookbox_server) #a really fancy way of saying host:8001 c.hookbox_server = parsed.scheme + "://" + parsed.hostname + ":" + config["hookbox_js_port"] return WSGIController.__call__(self, environ, start_response)
def validate_python(self, value, state): if value != authentication_token(): raise formencode.Invalid( self.message('invalid_token', state, search_number=value), value, state )
def __wrapper(self, func, *fargs, **fkwargs): cls = fargs[0] user = cls.authuser loc = "%s:%s" % (cls.__class__.__name__, func.__name__) # check if our IP is allowed ip_access_valid = True if not user.ip_allowed: from kallithea.lib import helpers as h h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))), category='warning') ip_access_valid = False # check if we used an APIKEY and it's a valid one # defined whitelist of controllers which API access will be enabled _api_key = request.GET.get('api_key', '') api_access_valid = allowed_api_access(loc, api_key=_api_key) # explicit controller is enabled or API is in our whitelist if self.api_access or api_access_valid: log.debug('Checking API KEY access for %s' % cls) if _api_key and _api_key in user.api_keys: api_access_valid = True log.debug('API KEY ****%s is VALID' % _api_key[-4:]) else: api_access_valid = False if not _api_key: log.debug("API KEY *NOT* present in request") else: log.warning("API KEY ****%s *NOT* valid" % _api_key[-4:]) # CSRF protection - POSTs with session auth must contain correct token if request.POST and user.is_authenticated and not api_access_valid: token = request.POST.get(secure_form.token_key) if not token or token != secure_form.authentication_token(): log.error('CSRF check failed') return abort(403) log.debug('Checking if %s is authenticated @ %s' % (user.username, loc)) reason = 'RegularAuth' if user.is_authenticated else 'APIAuth' if ip_access_valid and (user.is_authenticated or api_access_valid): log.info('user %s authenticating with:%s IS authenticated on func %s ' % (user, reason, loc) ) return func(*fargs, **fkwargs) else: log.warning('user %s authenticating with:%s NOT authenticated on func: %s: ' 'IP_ACCESS:%s API_ACCESS:%s' % (user, reason, loc, ip_access_valid, api_access_valid) ) p = url.current() log.debug('redirecting to login page with %s' % p) return redirect(url('login_home', came_from=p))
def __wrapper(self, func, *fargs, **fkwargs): controller = fargs[0] user = request.authuser loc = "%s:%s" % (controller.__class__.__name__, func.__name__) log.debug('Checking access for user %s @ %s', user, loc) if not AuthUser.check_ip_allowed(user, request.ip_addr): raise _redirect_to_login(_('IP %s not allowed') % request.ip_addr) # Check if we used an API key to authenticate. api_key = user.authenticating_api_key if api_key is not None: # Check that controller is enabled for API key usage. if not self.api_access and not allowed_api_access(loc, api_key=api_key): # controller does not allow API access log.warning('API access to %s is not allowed', loc) raise HTTPForbidden() log.info('user %s authenticated with API key ****%s @ %s', user, api_key[-4:], loc) return func(*fargs, **fkwargs) # CSRF protection: Whenever a request has ambient authority (whether # through a session cookie or its origin IP address), it must include # the correct token, unless the HTTP method is GET or HEAD (and thus # guaranteed to be side effect free. In practice, the only situation # where we allow side effects without ambient authority is when the # authority comes from an API key; and that is handled above. if request.method not in ['GET', 'HEAD']: token = request.POST.get(secure_form.token_key) if not token or token != secure_form.authentication_token(): log.error('CSRF check failed') raise HTTPForbidden() # regular user authentication if user.is_authenticated or user.is_default_user: log.info('user %s authenticated with regular auth @ %s', user, loc) return func(*fargs, **fkwargs) else: log.warning('user %s NOT authenticated with regular auth @ %s', user, loc) raise _redirect_to_login()
def validate_python(self, value, state): if value != authentication_token(): msg = M(self, 'invalid_token', state) raise formencode.Invalid(msg, value, state)
def form(self): request_config().environ = request.environ return secure_form.authentication_token()
def __wrapper(self, func, *fargs, **fkwargs): controller = fargs[0] user = controller.authuser loc = "%s:%s" % (controller.__class__.__name__, func.__name__) log.debug('Checking access for user %s @ %s', user, loc) if not AuthUser.check_ip_allowed(user, controller.ip_addr): raise _redirect_to_login(_('IP %s not allowed') % controller.ip_addr) # check if we used an API key and it's a valid one api_key = request.GET.get('api_key') if api_key is not None: # explicit controller is enabled or API is in our whitelist if self.api_access or allowed_api_access(loc, api_key=api_key): if api_key in user.api_keys: log.info('user %s authenticated with API key ****%s @ %s', user, api_key[-4:], loc) return func(*fargs, **fkwargs) else: log.warning('API key ****%s is NOT valid', api_key[-4:]) raise _redirect_to_login(_('Invalid API key')) else: # controller does not allow API access log.warning('API access to %s is not allowed', loc) raise HTTPForbidden() # Only allow the following HTTP request methods. (We sometimes use POST # requests with a '_method' set to 'PUT' or 'DELETE'; but that is only # used for the route lookup, and does not affect request.method.) if request.method not in ['GET', 'HEAD', 'POST', 'PUT']: raise HTTPMethodNotAllowed() # Make sure CSRF token never appears in the URL. If so, invalidate it. if secure_form.token_key in request.GET: log.error('CSRF key leak detected') session.pop(secure_form.token_key, None) session.save() from kallithea.lib import helpers as h h.flash(_("CSRF token leak has been detected - all form tokens have been expired"), category='error') # CSRF protection: Whenever a request has ambient authority (whether # through a session cookie or its origin IP address), it must include # the correct token, unless the HTTP method is GET or HEAD (and thus # guaranteed to be side effect free. In practice, the only situation # where we allow side effects without ambient authority is when the # authority comes from an API key; and that is handled above. if request.method not in ['GET', 'HEAD']: token = request.POST.get(secure_form.token_key) if not token or token != secure_form.authentication_token(): log.error('CSRF check failed') raise HTTPForbidden() # WebOb already ignores request payload parameters for anything other # than POST/PUT, but double-check since other Kallithea code relies on # this assumption. if request.method not in ['POST', 'PUT'] and request.POST: log.error('%r request with payload parameters; WebOb should have stopped this', request.method) raise HTTPBadRequest() # regular user authentication if user.is_authenticated or user.is_default_user: log.info('user %s authenticated with regular auth @ %s', user, loc) return func(*fargs, **fkwargs) else: log.warning('user %s NOT authenticated with regular auth @ %s', user, loc) raise _redirect_to_login()