Merge branch 'master' into 1.4-branch
| | |
| | | application. |
| | | |
| | | session factory |
| | | A callable, which, when called with a single argument named |
| | | ``request`` (a :term:`request` object), returns a |
| | | :term:`session` object. |
| | | A callable, which, when called with a single argument named ``request`` |
| | | (a :term:`request` object), returns a :term:`session` object. See |
| | | :ref:`using_the_default_session_factory`, |
| | | :ref:`using_alternate_session_factories` and |
| | | :meth:`pyramid.config.Configurator.set_session_factory` for more |
| | | information. |
| | | |
| | | Mako |
| | | `Mako <http://www.makotemplates.org/>`_ is a template language language |
| | |
| | | |
| | | The ``match_param`` argument passed to ``add_view``. |
| | | |
| | | ``csrf_token`` |
| | | |
| | | The ``csrf_token`` argument passed to ``add_view``. |
| | | |
| | | ``callable`` |
| | | |
| | | The (resolved) ``view`` argument passed to ``add_view``. Represents the |
| | |
| | | consideration when deciding whether or not to invoke the associated view |
| | | callable. |
| | | |
| | | ``check_csrf`` |
| | | If specified, this value should be one of ``None``, ``True``, ``False``, or |
| | | a string representing the 'check name'. If the value is ``True`` or a |
| | | string, CSRF checking will be performed. If the value is ``False`` or |
| | | ``None``, CSRF checking will not be performed. |
| | | |
| | | If the value provided is a string, that string will be used as the 'check |
| | | name'. If the value provided is ``True``, ``csrf_token`` will be used as |
| | | the check name. |
| | | |
| | | If CSRF checking is performed, the checked value will be the value of |
| | | ``request.params[check_name]``. This value will be compared against the |
| | | value of ``request.session.get_csrf_token()``, and the check will pass if |
| | | these two values are the same. If the check passes, the associated view |
| | | will be permitted to execute. If the check fails, the associated view |
| | | will not be permitted to execute. |
| | | |
| | | Note that using this feature requires a :term:`session factory` to have |
| | | been configured. |
| | | |
| | | .. versionadded:: 1.4a2 |
| | | |
| | | ``custom_predicates`` |
| | | If ``custom_predicates`` is specified, it must be a sequence of references |
| | | to custom predicate callables. Use custom predicates when no set of |
| | |
| | | If ``custom_predicates`` is not specified, no custom predicates are |
| | | used. |
| | | |
| | | ``predicates`` |
| | | Pass a key/value pair here to use a third-party predicate registered via |
| | | :meth:`pyramid.config.Configurator.add_view_predicate`. More than one |
| | | key/value pair can be used at the same time. See |
| | | :ref:`view_and_route_predicates` for more information about third-party |
| | | predicates. |
| | | |
| | | .. versionadded:: 1.4a1 |
| | | |
| | | .. index:: |
| | | single: view_config decorator |
| | | |
| | |
| | | - A new :func:`pyramid.session.check_csrf_token` convenience API function was |
| | | added. |
| | | |
| | | - A ``check_csrf`` view predicate was added. For example, you can now do |
| | | ``config.add_view(someview, check_csrf=True)``. When the predicate is |
| | | checked, if the ``csrf_token`` value in ``request.params`` matches the csrf |
| | | token in the request's session, the view will be permitted to execute. |
| | | Otherwise, it will not be permitted to execute. |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | |
| | | |
| | | from pyramid.util import object_description |
| | | |
| | | from pyramid.session import check_csrf_token |
| | | |
| | | from .util import as_sorted_tuple |
| | | |
| | | class XHRPredicate(object): |
| | |
| | | # injects ``traverse`` into the matchdict. As a result, we just |
| | | # return True. |
| | | return True |
| | | |
| | | class CheckCSRFTokenPredicate(object): |
| | | |
| | | check_csrf_token = staticmethod(check_csrf_token) # testing |
| | | |
| | | def __init__(self, val, config): |
| | | self.val = val |
| | | |
| | | def text(self): |
| | | return 'check_csrf = %s' % (self.val,) |
| | | |
| | | phash = text |
| | | |
| | | def __call__(self, context, request): |
| | | val = self.val |
| | | if val: |
| | | if val is True: |
| | | val = 'csrf_token' |
| | | return self.check_csrf_token(request, val, raises=False) |
| | | return True |
| | | |
| | |
| | | mapper=None, |
| | | http_cache=None, |
| | | match_param=None, |
| | | check_csrf=None, |
| | | **predicates): |
| | | """ Add a :term:`view configuration` to the current |
| | | configuration state. Arguments to ``add_view`` are broken |
| | |
| | | variable. If the regex matches, this predicate will be |
| | | ``True``. |
| | | |
| | | check_csrf |
| | | |
| | | If specified, this value should be one of ``None``, ``True``, |
| | | ``False``, or a string representing the 'check name'. If the value |
| | | is ``True`` or a string, CSRF checking will be performed. If the |
| | | value is ``False`` or ``None``, CSRF checking will not be performed. |
| | | |
| | | If the value provided is a string, that string will be used as the |
| | | 'check name'. If the value provided is ``True``, ``csrf_token`` will |
| | | be used as the check name. |
| | | |
| | | If CSRF checking is performed, the checked value will be the value |
| | | of ``request.params[check_name]``. This value will be compared |
| | | against the value of ``request.session.get_csrf_token()``, and the |
| | | check will pass if these two values are the same. If the check |
| | | passes, the associated view will be permitted to execute. If the |
| | | check fails, the associated view will not be permitted to execute. |
| | | |
| | | Note that using this feature requires a :term:`session factory` to |
| | | have been configured. |
| | | |
| | | .. versionadded:: 1.4a2 |
| | | |
| | | custom_predicates |
| | | |
| | | This value should be a sequence of references to custom |
| | |
| | | :meth:`pyramid.config.Configurator.add_view_predicate`. More than |
| | | one key/value pair can be used at the same time. See |
| | | :ref:`view_and_route_predicates` for more information about |
| | | third-party predicates. This argument is new as of Pyramid 1.4. |
| | | third-party predicates. |
| | | |
| | | .. versionadded: 1.4a1 |
| | | |
| | | """ |
| | | view = self.maybe_dotted(view) |
| | |
| | | containment=containment, |
| | | request_type=request_type, |
| | | match_param=match_param, |
| | | check_csrf=check_csrf, |
| | | custom=predvalseq(custom_predicates), |
| | | ) |
| | | ) |
| | |
| | | header=header, |
| | | path_info=path_info, |
| | | match_param=match_param, |
| | | check_csrf=check_csrf, |
| | | callable=view, |
| | | mapper=mapper, |
| | | decorator=decorator, |
| | |
| | | ('containment', p.ContainmentPredicate), |
| | | ('request_type', p.RequestTypePredicate), |
| | | ('match_param', p.MatchParamPredicate), |
| | | ('check_csrf', p.CheckCSRFTokenPredicate), |
| | | ('custom', p.CustomPredicate), |
| | | ): |
| | | self.add_view_predicate(name, factory) |
| | |
| | | |
| | | return pickle.loads(pickled) |
| | | |
| | | def check_csrf_token(request, token='csrf_token'): |
| | | def check_csrf_token(request, token='csrf_token', raises=True): |
| | | """ Check the CSRF token in the request's session against the value in |
| | | ``request.params.get(token)``. If ``token`` is not supplied, the string |
| | | value ``csrf_token`` will be used as the token value. If the value in |
| | | ``request.params.get(token)`` doesn't match the value supplied by |
| | | ``request.session.get_csrf_token()``, this function will raise an |
| | | :exc:`pyramid.httpexceptions.HTTPBadRequest` exception. If the CSRF |
| | | check is successful, this function will return ``True``. |
| | | ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this |
| | | function will raise an :exc:`pyramid.httpexceptions.HTTPBadRequest` |
| | | exception. If the check does succeed and ``raises`` is ``False``, this |
| | | function will return ``False``. If the CSRF check is successful, this |
| | | function will return ``True`` unconditionally. |
| | | |
| | | Note that using this function requires that a :term:`session factory` is |
| | | configured. |
| | | |
| | | .. versionadded:: 1.4a2 |
| | | """ |
| | | if request.params.get(token) != request.session.get_csrf_token(): |
| | | raise HTTPBadRequest('incorrect CSRF token') |
| | | if raises: |
| | | raise HTTPBadRequest('incorrect CSRF token') |
| | | return False |
| | | return True |
| | | |
| | | def UnencryptedCookieSessionFactoryConfig( |
| | |
| | | inst = self._makeOne('/abc') |
| | | self.assertEqual(inst.phash(), '') |
| | | |
| | | class Test_CheckCSRFTokenPredicate(unittest.TestCase): |
| | | def _makeOne(self, val, config): |
| | | from pyramid.config.predicates import CheckCSRFTokenPredicate |
| | | return CheckCSRFTokenPredicate(val, config) |
| | | |
| | | def test_text(self): |
| | | inst = self._makeOne(True, None) |
| | | self.assertEqual(inst.text(), 'check_csrf = True') |
| | | |
| | | def test_phash(self): |
| | | inst = self._makeOne(True, None) |
| | | self.assertEqual(inst.phash(), 'check_csrf = True') |
| | | |
| | | def test_it_call_val_True(self): |
| | | inst = self._makeOne(True, None) |
| | | request = Dummy() |
| | | def check_csrf_token(req, val, raises=True): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(val, 'csrf_token') |
| | | self.assertEqual(raises, False) |
| | | return True |
| | | inst.check_csrf_token = check_csrf_token |
| | | result = inst(None, request) |
| | | self.assertEqual(result, True) |
| | | |
| | | def test_it_call_val_str(self): |
| | | inst = self._makeOne('abc', None) |
| | | request = Dummy() |
| | | def check_csrf_token(req, val, raises=True): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(val, 'abc') |
| | | self.assertEqual(raises, False) |
| | | return True |
| | | inst.check_csrf_token = check_csrf_token |
| | | result = inst(None, request) |
| | | self.assertEqual(result, True) |
| | | |
| | | def test_it_call_val_False(self): |
| | | inst = self._makeOne(False, None) |
| | | request = Dummy() |
| | | result = inst(None, request) |
| | | self.assertEqual(result, True) |
| | | |
| | | class predicate(object): |
| | | def __repr__(self): |
| | | return 'predicate' |
| | |
| | | self.assertRaises(ValueError, self._callFUT, serialized, 'secret') |
| | | |
| | | class Test_check_csrf_token(unittest.TestCase): |
| | | def _callFUT(self, request, token): |
| | | def _callFUT(self, request, token, raises=True): |
| | | from ..session import check_csrf_token |
| | | return check_csrf_token(request, token) |
| | | return check_csrf_token(request, token, raises=raises) |
| | | |
| | | def test_success(self): |
| | | request = testing.DummyRequest() |
| | |
| | | request.params['csrf_token'] = request.session.get_csrf_token() |
| | | self.assertEqual(check_csrf_token(request), True) |
| | | |
| | | def test_failure(self): |
| | | def test_failure_raises(self): |
| | | from pyramid.httpexceptions import HTTPBadRequest |
| | | request = testing.DummyRequest() |
| | | self.assertRaises(HTTPBadRequest, self._callFUT, request, 'csrf_token') |
| | | |
| | | def test_failure_no_raises(self): |
| | | request = testing.DummyRequest() |
| | | result = self._callFUT(request, 'csrf_token', raises=False) |
| | | self.assertEqual(result, False) |
| | | |
| | | class DummySessionFactory(dict): |
| | | _dirty = False |
| | | _cookie_name = 'session' |
| | |
| | | ``request_type``, ``route_name``, ``request_method``, ``request_param``, |
| | | ``containment``, ``xhr``, ``accept``, ``header``, ``path_info``, |
| | | ``custom_predicates``, ``decorator``, ``mapper``, ``http_cache``, |
| | | ``match_param``, and ``predicates``. |
| | | ``match_param``, ``csrf_token``, and ``predicates``. |
| | | |
| | | The meanings of these arguments are the same as the arguments passed to |
| | | :meth:`pyramid.config.Configurator.add_view`. If any argument is left |