Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add support for multiple authentication challenges in WWW-Authenticate header#9242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
waxlamp wants to merge5 commits intoencode:master
base:master
Choose a base branch
Loading
fromwaxlamp:multiple-www-authenticate

Conversation

waxlamp
Copy link

This adds a setting to enable emitting a comma-separated list of challenges in theWWW-Authenticate header that is returned with a 401 response.

Fixes#7328 and resolves#7812.

ulgens reacted with rocket emojiulgens reacted with eyes emoji
@waxlampwaxlampforce-pushed themultiple-www-authenticate branch fromcc3a7e2 to525979eCompareJanuary 29, 2024 18:25
@@ -8,3 +8,4 @@ class RestFrameworkConfig(AppConfig):
def ready(self):
# Add System checks
from .checks import pagination_system_check # NOQA
from .checks import www_authenticate_behavior_setting_check # NOQA
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Is this line necessary? In my local build I was able to trigger the new error without it; I merely copied the pattern from the line above in my PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good question; have you been able to understand this further?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is following thisadvice from the Django docs:

Checks should be registered in a file that’s loaded when your application is loaded; for example, in theAppConfig.ready() method.

When you say you were able to trigger the new error without this: did this happen on startup, or when you rancheck manually?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think I understand this better now.

The@register decorator causes the check function to be registered; all that's required beyond using the decorator is to arrange to load the module in which those functions live. That's why omitting this line still allows my check to be performed (on both startup, and when invoking thecheck management command manually, as it happens): the previous line causes the whole module to load, which causes not justpagination_system_check but my new check function to be registered as well.

I tested this theory by removingboth lines; in that case, my check doesnot run. But this means that both lines can be replaced with justfrom . import checks; that's sufficient to register all the check functions in that module.

I hope all this made sense 🙂. If it does, I'll plan to make that change and resolve this conversation.

browniebroke reacted with thumbs up emoji
@auvipy
Copy link
Member

I am not sure what benefit this will provide?

@yarikoptic
Copy link
Contributor

I am not sure what benefit this will provide?

DRF supports having multiple alternative authentication schemes (which is great), but is not announcing that in the 401WWW-Authenticate response field, which makes it impossible to have a DRF-powered service which would play nicely with clients which follow the standard treatment of WWW-Authenticate header field: they would see only the first available authentication mechanism (e.g. some non-standard "Token") and not some other available and known by then how to handle alternative authentication mechanism. So it then requires client-side knowledge of what particular authentication schemes a given DRF-powered service actually supports.

@waxlamp
Copy link
Author

I am not sure what benefit this will provide?

Essentially, the value is in fulfilling theRFC's description ofWww-Authenticate in the face of a DRF application that offers multiple authorization schemes, but does not advertise most of them.

@staleStale
Copy link

stalebot commentedApr 27, 2025

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestalebot added the stale labelApr 27, 2025
@auvipyauvipy removed the stale labelApr 28, 2025
@auvipyauvipy requested a review froma teamApril 28, 2025 03:24
@@ -78,6 +78,7 @@
# Authentication
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
'UNAUTHENTICATED_TOKEN': None,
'WWW_AUTHENTICATE_BEHAVIOR': 'first',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why isn't this a boolean, e.g.WWW_AUTHENTICATE_ALL = False (by default)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I suppose I was leaving the door open for other modes beyond'first' and'all', but I think a boolean setting makes more sense here.

browniebroke reacted with thumbs up emoji
@@ -84,7 +84,7 @@ When an unauthenticated request is denied permission there are two different err
* [HTTP 401 Unauthorized][http401]
* [HTTP 403 Permission Denied][http403]

HTTP 401 responses must always include a `WWW-Authenticate` header, that instructs the client how to authenticate. HTTP 403 responses do not include the `WWW-Authenticate` header.
HTTP 401 responses must always include a `WWW-Authenticate` header, that instructs the client how to authenticate.The `www_authenticate_behavior` setting controls how the header is generated: if set to `'first'` (the default), then only the text for the first scheme in the list will be used; if set to `'all'`, then a comma-separated list of the text for all the schemes will be used (see [MDN WWW-Authenticate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate) for more details).HTTP 403 responses do not include the `WWW-Authenticate` header.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Setting name should be uppercase

Determines whether a single or multiple challenges are presented in the `WWW-Authenticate` header.

This should be set to `'first'` (the default value) or `'all'`. When set to `'first'`, the `WWW-Authenticate` header will be set to an appropriate challenge for the first authentication scheme in the list.
When set to `'all'`, a comma-separated list of the challenge for all specified authentication schemes will be used instead (following the [syntax specification](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

RFC 9110 also warns:

Some user agents do not recognize this form, however. As a result, sending a WWW-Authenticate field value with more than one member on the same field line might not be interoperable.

Perhaps we should have a similar warning somewhere, either here or inauthentication.md.

@@ -8,3 +8,4 @@ class RestFrameworkConfig(AppConfig):
def ready(self):
# Add System checks
from .checks import pagination_system_check # NOQA
from .checks import www_authenticate_behavior_setting_check # NOQA
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good question; have you been able to understand this further?

@@ -19,3 +19,22 @@ def pagination_system_check(app_configs, **kwargs):
)
)
return errors


@register(Tags.compatibility)
Copy link
Contributor

@peterthomassenpeterthomassenApr 28, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This probably should beTags.security, see for example all the checks inhttps://github.com/django/django/blob/0ee06c04e0256094270db3ffe8b5dafa6a8457a3/django/core/checks/security/base.py

Those checks also usedeploy=True, which causes them to only run withcheck --deploy. Not sure is this is a good idea. OTOH, it's done the same way for all the other validity checks for security settings.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I went withTags.compatibility largely because the other existing check is also looking to validate settings (which is all my check does, really).Tags.security seems to have more to do with actual security checks (rather than mere misconfiguration). Apparently it is also possible to omit the tag entirely.

I'm happy to go with any of these options, just let me know what you prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Sure, I have no strong preference.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@yarikopticyarikopticyarikoptic left review comments

@peterthomassenpeterthomassenpeterthomassen requested changes

@auvipyauvipyAwaiting requested review from auvipy

At least 1 approving review is required to merge this pull request.

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Multiple WWW-Authenticate headers in 401 responses
4 participants
@waxlamp@auvipy@yarikoptic@peterthomassen

[8]ページ先頭

©2009-2025 Movatter.jp