You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
How does webargs handle csrf token sent as part of form data? #640
Also I'm just a single person business so tide lift is too expensive for me.
If there's a way I can pay for one off support requests such as answering the question above at a much lower rate, I will be happy to do so.
I want greater responsiveness but I don't need such a huge level of support as what tide lift offers. I'm happy to write my code I just need questions that will receive guaranteed responses. I don't need super tight turnaround times. 2-3 days or even 2 weeks is fine
I'm not aware of the marshmallow projects having any support or contract option other than Tidelift. I'll leave it to others to answer if there's more to say on this.
webargs has no special handling for csrf-token. It's just "another field on the request" as far as we're concerned.
Since the CSRF token comes in on the POST body, I would expect it to arrive and need to be handled by your schema or parser, unless the middleware you're using removes it from the parsed body before sending it to your application code.
Assuming that's right, I see several options:
Add a csrf-token field to all of your schemas
Set your schemas to unknown=EXCLUDE or unknown=INCLUDE (rather than unknown=RAISE, the default)
Use a schema pre_load hook to remove a csrf-token field if one is present
Use a Django middleware to remove the field before it reaches webargs
(1-3) are marshmallow features, so the marshmallow docs should give you what you need. And (4) is really just a way in which webargs exposes a marshmallow feature (passing unknown to Schema.load).
That leaves (5), which is a webargs feature, and (6), which is a Django feature (and therefore beyond the scope of this project).
For (5), you could do
classMyParser(DjangoParser):
defpre_load(self, location_data, *, schema, req, location):
iflocation=="form"and"csrf-token"inlocation_data:
# `location_data` in the `form` case is a MultiDictProxy of an immutable django QueryDict# coerce to a dict to make it mutabledata=dict(location_data)
data.pop("csrf-token")
returndatareturnlocation_data
Are you one of the maintainers here? I did see that you have committed before to this repo.
I'm currently using a hackish way and conforms to your option 1. But I don't like that as it kinda of implies that this csrf_token is needed by the view (aka the controller endpoint of MVC) or by the model to save records, when actually that's not the case.
I will give 5 a shot.
Thank you for your excellent breakdown of my options 1-6. All those to do with webargs i have not heard before and it's awesome that you wrote them as they help me to better learn webargs.
I think we're good to close this. The necessary features to handle this case should all be there.
If we setup an "Example Gallery" in the docs, like the marshmallow examples page, I'd be happy to put the csrf-removing parser in there... That's the best documentation follow-up I can think of.
I'm closing this, but I'll open an issue to add an examples page.
but i am still unsure how to "call" the preload within my view function.
Here's my views.py
@use_args(draft_github_repo_total_args, location="form")
@require_http_methods(["POST"])
def github_repo_create_post(request, request_args):
if not request.user.is_authenticated:
return redirect(
"%s?next=%s" % (settings.LOGIN_URL, reverse_lazy("repos-create"))
)
...
So where do I call ?
I have ttried
webarg_parsers.py
from webargs.djangoparser import DjangoParser
class MyParser(DjangoParser):
"""
Note that Parser.pre_load is run after location loading
but before Schema.load is called.
It can therefore be called on multiple types of
mapping objects, including MultiDictProxy,
depending on what the location loader returns.
read https://webargs.readthedocs.io/en/latest/advanced.html#parser-pre-load
"""
def pre_load(self, location_data, *, schema, req, location):
if location == "form" and "csrfmiddlewaretoken" in location_data:
# `location_data` in the `form` case is a MultiDictProxy of an immutable django QueryDict
# coerce to a dict to make it mutable
data = dict(location_data)
data.pop("csrfmiddlewaretoken")
return data
return location_data
Then i get TypeError: pre_load() missing 3 required keyword-only arguments: 'schema', 'req', and 'location'
So I guess I am supposed to instantiate inside the view function ?I can roughly guess what i need to use to fill req and location but what about schema?
Parser pre_load gets called as part of the parser's use_args, use_kwargs, or parse invocation.
You haven't shown which use_args you're using, but I'm guessing that you're doing from webargs.djangoparser import use_args. That's just an alias for the default parser's use_args method.
Use the use_args decorator from the parser which defines the pre_load call instead:
parser=MyParser()
@parser.use_args(...) # <--- this, use_args from the parser, not the default parserdefview_func(...):
...
Activity
simkimsia commentedon Sep 20, 2021
Also I'm just a single person business so tide lift is too expensive for me.
If there's a way I can pay for one off support requests such as answering the question above at a much lower rate, I will be happy to do so.
I want greater responsiveness but I don't need such a huge level of support as what tide lift offers. I'm happy to write my code I just need questions that will receive guaranteed responses. I don't need super tight turnaround times. 2-3 days or even 2 weeks is fine
sirosen commentedon Sep 29, 2021
I'm not aware of the marshmallow projects having any support or contract option other than Tidelift. I'll leave it to others to answer if there's more to say on this.
webargshas no special handling forcsrf-token. It's just "another field on the request" as far as we're concerned.Since the CSRF token comes in on the POST body, I would expect it to arrive and need to be handled by your schema or parser, unless the middleware you're using removes it from the parsed body before sending it to your application code.
Assuming that's right, I see several options:
csrf-tokenfield to all of your schemasunknown=EXCLUDEorunknown=INCLUDE(rather thanunknown=RAISE, the default)pre_loadhook to remove acsrf-tokenfield if one is presentunknown=EXCLUDEorunknown=INCLUDEsee doc on setting unknownpre_loadhook to remove acsrf-tokenfield if one is present see doc on Parser.pre_load(1-3) are marshmallow features, so the marshmallow docs should give you what you need. And (4) is really just a way in which
webargsexposes a marshmallow feature (passingunknowntoSchema.load).That leaves (5), which is a webargs feature, and (6), which is a Django feature (and therefore beyond the scope of this project).
For (5), you could do
simkimsia commentedon Sep 30, 2021
thank you, @sirosen
Are you one of the maintainers here? I did see that you have committed before to this repo.
I'm currently using a hackish way and conforms to your option 1. But I don't like that as it kinda of implies that this csrf_token is needed by the view (aka the controller endpoint of MVC) or by the model to save records, when actually that's not the case.
I will give 5 a shot.
Thank you for your excellent breakdown of my options 1-6. All those to do with webargs i have not heard before and it's awesome that you wrote them as they help me to better learn webargs.
lafrech commentedon Sep 30, 2021
He is and I think we ought to update AUTHORS.rst.
sirosen commentedon Oct 4, 2021
I think we're good to close this. The necessary features to handle this case should all be there.
If we setup an "Example Gallery" in the docs, like the
marshmallowexamples page, I'd be happy to put the csrf-removing parser in there... That's the best documentation follow-up I can think of.I'm closing this, but I'll open an issue to add an examples page.
simkimsia commentedon Oct 5, 2021
@sirosen
Apologies, I only have time to try this out now.
I have a question. I have read https://webargs.readthedocs.io/en/latest/advanced.html#parser-pre-load
but i am still unsure how to "call" the preload within my view function.
Here's my views.py
So where do I call ?
I have ttried
webarg_parsers.py
Then i get
TypeError: pre_load() missing 3 required keyword-only arguments: 'schema', 'req', and 'location'So I guess I am supposed to instantiate inside the view function ?I can roughly guess what i need to use to fill req and location but what about schema?
sirosen commentedon Oct 5, 2021
Parser
pre_loadgets called as part of the parser'suse_args,use_kwargs, orparseinvocation.You haven't shown which
use_argsyou're using, but I'm guessing that you're doingfrom webargs.djangoparser import use_args. That's just an alias for the default parser'suse_argsmethod.Use the
use_argsdecorator from the parser which defines thepre_loadcall instead:simkimsia commentedon Oct 6, 2021
Works. Thank you @sirosen