Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pyramid/config/security.py : 71%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from zope.interface import implementer
3from pyramid.interfaces import (
4 IAuthorizationPolicy,
5 IAuthenticationPolicy,
6 ICSRFStoragePolicy,
7 IDefaultCSRFOptions,
8 IDefaultPermission,
9 PHASE1_CONFIG,
10 PHASE2_CONFIG,
11)
13from pyramid.csrf import LegacySessionCSRFStoragePolicy
14from pyramid.exceptions import ConfigurationError
15from pyramid.util import as_sorted_tuple
17from pyramid.config.actions import action_method
20class SecurityConfiguratorMixin(object):
21 def add_default_security(self):
22 self.set_csrf_storage_policy(LegacySessionCSRFStoragePolicy())
24 @action_method
25 def set_authentication_policy(self, policy):
26 """ Override the :app:`Pyramid` :term:`authentication policy` in the
27 current configuration. The ``policy`` argument must be an instance
28 of an authentication policy or a :term:`dotted Python name`
29 that points at an instance of an authentication policy.
31 .. note::
33 Using the ``authentication_policy`` argument to the
34 :class:`pyramid.config.Configurator` constructor can be used to
35 achieve the same purpose.
37 """
39 def register():
40 self._set_authentication_policy(policy)
41 if self.registry.queryUtility(IAuthorizationPolicy) is None:
42 raise ConfigurationError(
43 'Cannot configure an authentication policy without '
44 'also configuring an authorization policy '
45 '(use the set_authorization_policy method)'
46 )
48 intr = self.introspectable(
49 'authentication policy',
50 None,
51 self.object_description(policy),
52 'authentication policy',
53 )
54 intr['policy'] = policy
55 # authentication policy used by view config (phase 3)
56 self.action(
57 IAuthenticationPolicy,
58 register,
59 order=PHASE2_CONFIG,
60 introspectables=(intr,),
61 )
63 def _set_authentication_policy(self, policy):
64 policy = self.maybe_dotted(policy)
65 self.registry.registerUtility(policy, IAuthenticationPolicy)
67 @action_method
68 def set_authorization_policy(self, policy):
69 """ Override the :app:`Pyramid` :term:`authorization policy` in the
70 current configuration. The ``policy`` argument must be an instance
71 of an authorization policy or a :term:`dotted Python name` that points
72 at an instance of an authorization policy.
74 .. note::
76 Using the ``authorization_policy`` argument to the
77 :class:`pyramid.config.Configurator` constructor can be used to
78 achieve the same purpose.
79 """
81 def register():
82 self._set_authorization_policy(policy)
84 def ensure():
85 if self.autocommit:
86 return
87 if self.registry.queryUtility(IAuthenticationPolicy) is None:
88 raise ConfigurationError(
89 'Cannot configure an authorization policy without '
90 'also configuring an authentication policy '
91 '(use the set_authorization_policy method)'
92 )
94 intr = self.introspectable(
95 'authorization policy',
96 None,
97 self.object_description(policy),
98 'authorization policy',
99 )
100 intr['policy'] = policy
101 # authorization policy used by view config (phase 3) and
102 # authentication policy (phase 2)
103 self.action(
104 IAuthorizationPolicy,
105 register,
106 order=PHASE1_CONFIG,
107 introspectables=(intr,),
108 )
109 self.action(None, ensure)
111 def _set_authorization_policy(self, policy):
112 policy = self.maybe_dotted(policy)
113 self.registry.registerUtility(policy, IAuthorizationPolicy)
115 @action_method
116 def set_default_permission(self, permission):
117 """
118 Set the default permission to be used by all subsequent
119 :term:`view configuration` registrations. ``permission``
120 should be a :term:`permission` string to be used as the
121 default permission. An example of a permission
122 string:``'view'``. Adding a default permission makes it
123 unnecessary to protect each view configuration with an
124 explicit permission, unless your application policy requires
125 some exception for a particular view.
127 If a default permission is *not* set, views represented by
128 view configuration registrations which do not explicitly
129 declare a permission will be executable by entirely anonymous
130 users (any authorization policy is ignored).
132 Later calls to this method override will conflict with earlier calls;
133 there can be only one default permission active at a time within an
134 application.
136 .. warning::
138 If a default permission is in effect, view configurations meant to
139 create a truly anonymously accessible view (even :term:`exception
140 view` views) *must* use the value of the permission importable as
141 :data:`pyramid.security.NO_PERMISSION_REQUIRED`. When this string
142 is used as the ``permission`` for a view configuration, the default
143 permission is ignored, and the view is registered, making it
144 available to all callers regardless of their credentials.
146 .. seealso::
148 See also :ref:`setting_a_default_permission`.
150 .. note::
152 Using the ``default_permission`` argument to the
153 :class:`pyramid.config.Configurator` constructor can be used to
154 achieve the same purpose.
155 """
157 def register():
158 self.registry.registerUtility(permission, IDefaultPermission)
160 intr = self.introspectable(
161 'default permission', None, permission, 'default permission'
162 )
163 intr['value'] = permission
164 perm_intr = self.introspectable(
165 'permissions', permission, permission, 'permission'
166 )
167 perm_intr['value'] = permission
168 # default permission used during view registration (phase 3)
169 self.action(
170 IDefaultPermission,
171 register,
172 order=PHASE1_CONFIG,
173 introspectables=(intr, perm_intr),
174 )
176 def add_permission(self, permission_name):
177 """
178 A configurator directive which registers a free-standing
179 permission without associating it with a view callable. This can be
180 used so that the permission shows up in the introspectable data under
181 the ``permissions`` category (permissions mentioned via ``add_view``
182 already end up in there). For example::
184 config = Configurator()
185 config.add_permission('view')
186 """
187 intr = self.introspectable(
188 'permissions', permission_name, permission_name, 'permission'
189 )
190 intr['value'] = permission_name
191 self.action(None, introspectables=(intr,))
193 @action_method
194 def set_default_csrf_options(
195 self,
196 require_csrf=True,
197 token='csrf_token',
198 header='X-CSRF-Token',
199 safe_methods=('GET', 'HEAD', 'OPTIONS', 'TRACE'),
200 callback=None,
201 ):
202 """
203 Set the default CSRF options used by subsequent view registrations.
205 ``require_csrf`` controls whether CSRF checks will be automatically
206 enabled on each view in the application. This value is used as the
207 fallback when ``require_csrf`` is left at the default of ``None`` on
208 :meth:`pyramid.config.Configurator.add_view`.
210 ``token`` is the name of the CSRF token used in the body of the
211 request, accessed via ``request.POST[token]``. Default: ``csrf_token``.
213 ``header`` is the name of the header containing the CSRF token,
214 accessed via ``request.headers[header]``. Default: ``X-CSRF-Token``.
216 If ``token`` or ``header`` are set to ``None`` they will not be used
217 for checking CSRF tokens.
219 ``safe_methods`` is an iterable of HTTP methods which are expected to
220 not contain side-effects as defined by RFC2616. Safe methods will
221 never be automatically checked for CSRF tokens.
222 Default: ``('GET', 'HEAD', 'OPTIONS', TRACE')``.
224 If ``callback`` is set, it must be a callable accepting ``(request)``
225 and returning ``True`` if the request should be checked for a valid
226 CSRF token. This callback allows an application to support
227 alternate authentication methods that do not rely on cookies which
228 are not subject to CSRF attacks. For example, if a request is
229 authenticated using the ``Authorization`` header instead of a cookie,
230 this may return ``False`` for that request so that clients do not
231 need to send the ``X-CSRF-Token`` header. The callback is only tested
232 for non-safe methods as defined by ``safe_methods``.
234 .. versionadded:: 1.7
236 .. versionchanged:: 1.8
237 Added the ``callback`` option.
239 """
240 options = DefaultCSRFOptions(
241 require_csrf, token, header, safe_methods, callback
242 )
244 def register():
245 self.registry.registerUtility(options, IDefaultCSRFOptions)
247 intr = self.introspectable(
248 'default csrf view options',
249 None,
250 options,
251 'default csrf view options',
252 )
253 intr['require_csrf'] = require_csrf
254 intr['token'] = token
255 intr['header'] = header
256 intr['safe_methods'] = as_sorted_tuple(safe_methods)
257 intr['callback'] = callback
259 self.action(
260 IDefaultCSRFOptions,
261 register,
262 order=PHASE1_CONFIG,
263 introspectables=(intr,),
264 )
266 @action_method
267 def set_csrf_storage_policy(self, policy):
268 """
269 Set the :term:`CSRF storage policy` used by subsequent view
270 registrations.
272 ``policy`` is a class that implements the
273 :meth:`pyramid.interfaces.ICSRFStoragePolicy` interface and defines
274 how to generate and persist CSRF tokens.
276 """
278 def register():
279 self.registry.registerUtility(policy, ICSRFStoragePolicy)
281 intr = self.introspectable(
282 'csrf storage policy', None, policy, 'csrf storage policy'
283 )
284 intr['policy'] = policy
285 self.action(ICSRFStoragePolicy, register, introspectables=(intr,))
288@implementer(IDefaultCSRFOptions)
289class DefaultCSRFOptions(object):
290 def __init__(self, require_csrf, token, header, safe_methods, callback):
291 self.require_csrf = require_csrf
292 self.token = token
293 self.header = header
294 self.safe_methods = frozenset(safe_methods)
295 self.callback = callback