Add global CSRF protection
This commit is contained in:
parent
ab09314ed3
commit
4ed522ae47
|
@ -129,6 +129,9 @@ def make_pyramid_config(settings):
|
||||||
config.set_authentication_policy(SessionAuthenticationPolicy())
|
config.set_authentication_policy(SessionAuthenticationPolicy())
|
||||||
config.set_authorization_policy(TailboneAuthorizationPolicy())
|
config.set_authorization_policy(TailboneAuthorizationPolicy())
|
||||||
|
|
||||||
|
# always require CSRF token protection
|
||||||
|
config.set_default_csrf_options(require_csrf=True, token='_csrf')
|
||||||
|
|
||||||
# Bring in some Pyramid goodies.
|
# Bring in some Pyramid goodies.
|
||||||
config.include('pyramid_beaker')
|
config.include('pyramid_beaker')
|
||||||
config.include('pyramid_mako')
|
config.include('pyramid_mako')
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from formencode import Schema
|
from formencode import Schema
|
||||||
|
|
||||||
from .core import Form, Field, FieldSet, GenericFieldSet, invalid_csrf_token
|
from .core import Form, Field, FieldSet, GenericFieldSet
|
||||||
from .simpleform import SimpleForm, FormRenderer
|
from .simpleform import SimpleForm, FormRenderer
|
||||||
from .alchemy import AlchemyForm
|
from .alchemy import AlchemyForm
|
||||||
from .fields import AssociationProxyField
|
from .fields import AssociationProxyField
|
||||||
|
|
|
@ -33,7 +33,6 @@ from pyramid.renderers import render
|
||||||
from webhelpers.html import HTML, tags
|
from webhelpers.html import HTML, tags
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.forms import invalid_csrf_token
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateEngine(fa.templates.TemplateEngine):
|
class TemplateEngine(fa.templates.TemplateEngine):
|
||||||
|
@ -114,8 +113,5 @@ class AlchemyForm(Object):
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if invalid_csrf_token(self.request):
|
|
||||||
self.request.session.flash("Invalid CSRF token", 'error')
|
|
||||||
return False
|
|
||||||
self.fieldset.rebind(data=self.request.params)
|
self.fieldset.rebind(data=self.request.params)
|
||||||
return self.fieldset.validate()
|
return self.fieldset.validate()
|
||||||
|
|
|
@ -33,17 +33,6 @@ from formalchemy.helpers import content_tag
|
||||||
from pyramid.renderers import render
|
from pyramid.renderers import render
|
||||||
|
|
||||||
|
|
||||||
def invalid_csrf_token(request):
|
|
||||||
"""
|
|
||||||
Returns boolean indicating whether the given request has an *invalid* CSRF token.
|
|
||||||
"""
|
|
||||||
if request.method == 'POST':
|
|
||||||
csrf_token = request.session.get_csrf_token()
|
|
||||||
if request.POST.get('_csrf') != csrf_token:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class Form(object):
|
class Form(object):
|
||||||
"""
|
"""
|
||||||
Base class for all forms.
|
Base class for all forms.
|
||||||
|
|
|
@ -33,7 +33,7 @@ from pyramid_simpleform import renderers
|
||||||
from webhelpers.html import tags
|
from webhelpers.html import tags
|
||||||
from webhelpers.html import HTML
|
from webhelpers.html import HTML
|
||||||
|
|
||||||
from tailbone.forms import Form, invalid_csrf_token
|
from tailbone.forms import Form
|
||||||
|
|
||||||
|
|
||||||
class SimpleForm(Form):
|
class SimpleForm(Form):
|
||||||
|
@ -53,9 +53,6 @@ class SimpleForm(Form):
|
||||||
return super(SimpleForm, self).render(**kwargs)
|
return super(SimpleForm, self).render(**kwargs)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if invalid_csrf_token(self.request):
|
|
||||||
self.request.session.flash("Invalid CSRF token", 'error')
|
|
||||||
return False
|
|
||||||
return self._form.validate()
|
return self._form.validate()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ from rattail.util import pretty_quantity
|
||||||
from webhelpers.html import *
|
from webhelpers.html import *
|
||||||
from webhelpers.html.tags import *
|
from webhelpers.html.tags import *
|
||||||
|
|
||||||
from tailbone.util import pretty_datetime
|
from tailbone.util import csrf_token, pretty_datetime
|
||||||
|
|
||||||
|
|
||||||
def pretty_date(date):
|
def pretty_date(date):
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${h.form(url('change_password'))}
|
${h.form(url('change_password'))}
|
||||||
|
${form.csrf_token()}
|
||||||
${form.referrer_field()}
|
${form.referrer_field()}
|
||||||
${form.field_div('current_password', form.password('current_password'))}
|
${form.field_div('current_password', form.password('current_password'))}
|
||||||
${form.field_div('new_password', form.password('new_password'))}
|
${form.field_div('new_password', form.password('new_password'))}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${form.begin()}
|
${form.begin()}
|
||||||
|
${form.csrf_token()}
|
||||||
${form.hidden('user', value=request.user.uuid if request.user else None)}
|
${form.hidden('user', value=request.user.uuid if request.user else None)}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
${h.form(request.current_route_url())}
|
${h.form(request.current_route_url())}
|
||||||
|
${h.csrf_token(request)}
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
|
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
|
||||||
<button type="button" id="confirm-delete">Yes, please DELETE this data forever!</button>
|
<button type="button" id="confirm-delete">Yes, please DELETE this data forever!</button>
|
||||||
|
|
|
@ -71,6 +71,7 @@ ${rows_grid|n}
|
||||||
<div id="execution-options-dialog" style="display: none;">
|
<div id="execution-options-dialog" style="display: none;">
|
||||||
|
|
||||||
${h.form(url('{}.execute'.format(route_prefix), uuid=batch.uuid), name='batch-execution')}
|
${h.form(url('{}.execute'.format(route_prefix), uuid=batch.uuid), name='batch-execution')}
|
||||||
|
${h.csrf_token(request)}
|
||||||
% if master.has_execution_options:
|
% if master.has_execution_options:
|
||||||
${rendered_execution_options|n}
|
${rendered_execution_options|n}
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<div class="form">
|
<div class="form">
|
||||||
|
|
||||||
${h.form(request.current_route_url())}
|
${h.form(request.current_route_url())}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label for="batch_type">Batch Type</label>
|
<label for="batch_type">Batch Type</label>
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
<div class="form">
|
<div class="form">
|
||||||
|
|
||||||
${h.form(request.current_route_url())}
|
${h.form(request.current_route_url())}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label for="provider">Batch Type</label>
|
<label for="provider">Batch Type</label>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
${h.form(request.current_route_url())}
|
${h.form(request.current_route_url())}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label for="department">Department</label>
|
<label for="department">Department</label>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<div class="timesheet-wrapper">
|
<div class="timesheet-wrapper">
|
||||||
|
|
||||||
${form.begin(id='filter-form')}
|
${form.begin(id='filter-form')}
|
||||||
|
${form.csrf_token()}
|
||||||
|
|
||||||
<table class="timesheet-header">
|
<table class="timesheet-header">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -283,6 +283,7 @@
|
||||||
|
|
||||||
<%def name="edit_form()">
|
<%def name="edit_form()">
|
||||||
${h.form(url('schedule.edit'), id='schedule-form')}
|
${h.form(url('schedule.edit'), id='schedule-form')}
|
||||||
|
${h.csrf_token(request)}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="edit_tools()">
|
<%def name="edit_tools()">
|
||||||
|
@ -299,6 +300,7 @@ ${timesheet_wrapper(edit_form=edit_form, edit_tools=edit_tools, context_menu=con
|
||||||
${edit_tools()}
|
${edit_tools()}
|
||||||
|
|
||||||
${h.form(url('schedule.edit'), id="clear-schedule-form")}
|
${h.form(url('schedule.edit'), id="clear-schedule-form")}
|
||||||
|
${h.csrf_token(request)}
|
||||||
${h.hidden('clear-schedule', value='clear')}
|
${h.hidden('clear-schedule', value='clear')}
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
|
|
||||||
|
@ -318,6 +320,7 @@ ${h.end_form()}
|
||||||
and then new shifts will be created based on the week you specify.
|
and then new shifts will be created based on the week you specify.
|
||||||
</p>
|
</p>
|
||||||
${h.form(url('schedule.edit'), id='copy-schedule-form')}
|
${h.form(url('schedule.edit'), id='copy-schedule-form')}
|
||||||
|
${h.csrf_token(request)}
|
||||||
<label for="copy-week">Copy from week:</label>
|
<label for="copy-week">Copy from week:</label>
|
||||||
${h.text('copy-week')}
|
${h.text('copy-week')}
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
|
|
|
@ -31,11 +31,21 @@ import datetime
|
||||||
import pytz
|
import pytz
|
||||||
import humanize
|
import humanize
|
||||||
|
|
||||||
from webhelpers.html import HTML
|
from webhelpers.html import HTML, tags
|
||||||
|
|
||||||
from rattail.time import timezone, make_utc
|
from rattail.time import timezone, make_utc
|
||||||
|
|
||||||
|
|
||||||
|
def csrf_token(request, name='_csrf'):
|
||||||
|
"""
|
||||||
|
Convenience function. Returns CSRF hidden tag inside hidden DIV.
|
||||||
|
"""
|
||||||
|
token = request.session.get_csrf_token()
|
||||||
|
if token is None:
|
||||||
|
token = request.session.new_csrf_token()
|
||||||
|
return HTML.tag("div", tags.hidden(name, value=token), style="display:none;")
|
||||||
|
|
||||||
|
|
||||||
def pretty_datetime(config, value):
|
def pretty_datetime(config, value):
|
||||||
"""
|
"""
|
||||||
Formats a datetime as a "pretty" human-readable string, with a tooltip
|
Formats a datetime as a "pretty" human-readable string, with a tooltip
|
||||||
|
|
Loading…
Reference in a new issue