Hide keyboard shortcuts

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 

2 

3from pyramid.interfaces import ( 

4 IAuthorizationPolicy, 

5 IAuthenticationPolicy, 

6 ICSRFStoragePolicy, 

7 IDefaultCSRFOptions, 

8 IDefaultPermission, 

9 PHASE1_CONFIG, 

10 PHASE2_CONFIG, 

11) 

12 

13from pyramid.csrf import LegacySessionCSRFStoragePolicy 

14from pyramid.exceptions import ConfigurationError 

15from pyramid.util import as_sorted_tuple 

16 

17from pyramid.config.actions import action_method 

18 

19 

20class SecurityConfiguratorMixin(object): 

21 def add_default_security(self): 

22 self.set_csrf_storage_policy(LegacySessionCSRFStoragePolicy()) 

23 

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. 

30 

31 .. note:: 

32 

33 Using the ``authentication_policy`` argument to the 

34 :class:`pyramid.config.Configurator` constructor can be used to 

35 achieve the same purpose. 

36 

37 """ 

38 

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 ) 

47 

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 ) 

62 

63 def _set_authentication_policy(self, policy): 

64 policy = self.maybe_dotted(policy) 

65 self.registry.registerUtility(policy, IAuthenticationPolicy) 

66 

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. 

73 

74 .. note:: 

75 

76 Using the ``authorization_policy`` argument to the 

77 :class:`pyramid.config.Configurator` constructor can be used to 

78 achieve the same purpose. 

79 """ 

80 

81 def register(): 

82 self._set_authorization_policy(policy) 

83 

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 ) 

93 

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) 

110 

111 def _set_authorization_policy(self, policy): 

112 policy = self.maybe_dotted(policy) 

113 self.registry.registerUtility(policy, IAuthorizationPolicy) 

114 

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. 

126 

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). 

131 

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. 

135 

136 .. warning:: 

137 

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. 

145 

146 .. seealso:: 

147 

148 See also :ref:`setting_a_default_permission`. 

149 

150 .. note:: 

151 

152 Using the ``default_permission`` argument to the 

153 :class:`pyramid.config.Configurator` constructor can be used to 

154 achieve the same purpose. 

155 """ 

156 

157 def register(): 

158 self.registry.registerUtility(permission, IDefaultPermission) 

159 

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 ) 

175 

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:: 

183 

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,)) 

192 

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. 

204 

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`. 

209 

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``. 

212 

213 ``header`` is the name of the header containing the CSRF token, 

214 accessed via ``request.headers[header]``. Default: ``X-CSRF-Token``. 

215 

216 If ``token`` or ``header`` are set to ``None`` they will not be used 

217 for checking CSRF tokens. 

218 

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')``. 

223 

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``. 

233 

234 .. versionadded:: 1.7 

235 

236 .. versionchanged:: 1.8 

237 Added the ``callback`` option. 

238 

239 """ 

240 options = DefaultCSRFOptions( 

241 require_csrf, token, header, safe_methods, callback 

242 ) 

243 

244 def register(): 

245 self.registry.registerUtility(options, IDefaultCSRFOptions) 

246 

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 

258 

259 self.action( 

260 IDefaultCSRFOptions, 

261 register, 

262 order=PHASE1_CONFIG, 

263 introspectables=(intr,), 

264 ) 

265 

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. 

271 

272 ``policy`` is a class that implements the 

273 :meth:`pyramid.interfaces.ICSRFStoragePolicy` interface and defines 

274 how to generate and persist CSRF tokens. 

275 

276 """ 

277 

278 def register(): 

279 self.registry.registerUtility(policy, ICSRFStoragePolicy) 

280 

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,)) 

286 

287 

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