Commit e53fb6c8 authored by Serge S. Koval's avatar Serge S. Koval

Merge pull request #1053 from pawl/actions_csrf

Simplify implementing CSRF validation by adding SecureForm
parents 128d5e00 46958eb0
...@@ -3,6 +3,21 @@ ...@@ -3,6 +3,21 @@
Advanced Functionality Advanced Functionality
====================== ======================
Enabling CSRF Validation
------------------------
To add CSRF protection to the forms that are generated by *ModelView* instances, use the
SecureForm class in your *ModelView* subclass by specifying the *form_base_class* parameter::
from flask_admin.form import SecureForm
from flask_admin.contrib.sqla import ModelView
class CarAdmin(ModelView):
form_base_class = SecureForm
SecureForm requires WTForms 2 or greater. It uses the WTForms SessionCSRF class
to generate the tokens for you, and validate them when the forms are submitted.
Localization With Flask-Babelex Localization With Flask-Babelex
------------------------------- -------------------------------
......
...@@ -55,27 +55,6 @@ There are many options available for customizing the display and functionality o ...@@ -55,27 +55,6 @@ There are many options available for customizing the display and functionality o
For more details on that, see :ref:`customising-builtin-views`. For more details on the other For more details on that, see :ref:`customising-builtin-views`. For more details on the other
ORM backends that are available, see :ref:`database-backends`. ORM backends that are available, see :ref:`database-backends`.
Enabling CSRF Validation
------------------------
To add CSRF protection to the forms that are generated by *ModelView* instances, use the
`FlaskWTF <https://flask-wtf.readthedocs.org/>`_ form class in your *ModelView*
subclass by specifying the *form_base_class* parameter::
from flask_admin.contrib.sqla import ModelView
import flask_wtf
# Flask and Flask-SQLAlchemy initialization here
app.config['CSRF_ENABLED'] = True
flask_wtf.CsrfProtect(app)
class MicroBlogModelView(ModelView):
form_base_class = flask_wtf.Form
The FlaskWTF form class comes with CSRF protection builtin, so it will generate
the tokens for you, and validate them when the forms are submitted.
Adding Content to the Index Page Adding Content to the Index Page
-------------------------------- --------------------------------
The first thing you'll notice when you visit `http://localhost:5000/admin/ <http://localhost:5000/admin/>`_ The first thing you'll notice when you visit `http://localhost:5000/admin/ <http://localhost:5000/admin/>`_
......
from wtforms import form from wtforms import form, __version__ as wtforms_version
from wtforms.fields.core import UnboundField from wtforms.fields.core import UnboundField
from .fields import * from .fields import *
...@@ -32,3 +32,29 @@ def recreate_field(unbound): ...@@ -32,3 +32,29 @@ def recreate_field(unbound):
raise ValueError('recreate_field expects UnboundField instance, %s was passed.' % type(unbound)) raise ValueError('recreate_field expects UnboundField instance, %s was passed.' % type(unbound))
return unbound.field_class(*unbound.args, **unbound.kwargs) return unbound.field_class(*unbound.args, **unbound.kwargs)
if int(wtforms_version[0]) > 1:
# only WTForms 2+ has built-in CSRF functionality
from os import urandom
from flask import session
from wtforms.csrf.session import SessionCSRF
class SecureForm(BaseForm):
"""
BaseForm with CSRF token generation and validation support.
Requires WTForms 2+
"""
class Meta:
csrf = True
csrf_class = SessionCSRF
csrf_secret = urandom(24)
@property
def csrf_context(self):
return session
else:
class SecureForm(BaseForm):
def __init__(self, *args, **kwargs):
raise Exception("SecureForm requires WTForms 2+")
...@@ -2,7 +2,7 @@ import wtforms ...@@ -2,7 +2,7 @@ import wtforms
from nose.tools import eq_, ok_ from nose.tools import eq_, ok_
from flask import Flask, session from flask import Flask
from werkzeug.wsgi import DispatcherMiddleware from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.test import Client from werkzeug.test import Client
...@@ -349,28 +349,11 @@ def test_form(): ...@@ -349,28 +349,11 @@ def test_form():
@wtforms2_and_up @wtforms2_and_up
def test_csrf(): def test_csrf():
from datetime import timedelta
from wtforms.csrf.session import SessionCSRF
from wtforms.meta import DefaultMeta
# BaseForm w/ CSRF
class SecureForm(form.BaseForm):
class Meta(DefaultMeta):
csrf = True
csrf_class = SessionCSRF
csrf_secret = b'EPj00jpfj8Gx1SjnyLxwBBSQfnQ9DJYe0Ym'
csrf_time_limit = timedelta(minutes=20)
@property
def csrf_context(self):
return session
class SecureModelView(MockModelView): class SecureModelView(MockModelView):
form_base_class = SecureForm form_base_class = form.SecureForm
def scaffold_form(self): def scaffold_form(self):
return SecureForm return form.SecureForm
def get_csrf_token(data): def get_csrf_token(data):
data = data.split('name="csrf_token" type="hidden" value="')[1] data = data.split('name="csrf_token" type="hidden" value="')[1]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment