From ae67776ad4d8e3069cabe08de52a3011b4be4d26 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 24 Jan 2024 20:50:17 -0500 Subject: [PATCH] Add support for "Authorization: Bearer KEY" to follow the RFC 6750 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ATM non-authenticated request is receiving 401 response with "Bearer" as the auth-scheme: ❯ curl --verbose -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/' 2>&1 | grep WW-A < WWW-Authenticate: Bearer realm="api" But according to the https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes and in particular https://datatracker.ietf.org/doc/html/rfc6750 for such request client should provide "Authorization: Bearer KEY" not "Authorization: token KEY". This commit adds support for both so we could follow the standard and retain support of already implemented client solutions. Such approach is also taken by GitHub API: https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api?apiVersion=2022-11-28 Verification of functionality: ❯ curl -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/' {"detail":"Authentication credentials were not provided."}% ❯ curl -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/?content_disposition=attachment' -H 'Authorization: Bearer 21a587dff19ec6956364443b97414d8bb4331b09' MYDATA ❯ curl -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/?content_disposition=attachment' -H 'Authorization: token 21a587dff19ec6956364443b97414d8bb4331b09' MYDATA ❯ curl -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/?content_disposition=attachment' -H 'Authorization: Token 21a587dff19ec6956364443b97414d8bb4331b09' MYDATA ❯ curl -J -L -X 'GET' 'http://localhost:8000/api/assets/ac212d93-525a-4454-afdd-85b90aad6143/download/?content_disposition=attachment' -H 'Authorization: dragon 21a587dff19ec6956364443b97414d8bb4331b09' {"detail":"Authentication credentials were not provided."} Closes #1825 --- DEVELOPMENT.md | 3 ++- dandiapi/api/auth.py | 16 ++++++++++++++++ dandiapi/settings.py | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 dandiapi/api/auth.py diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b2695a990..c6a888720 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -128,7 +128,8 @@ Then go to `/swagger` and use `GET /auth/token` end-point. ### Supplying the Token In API endpoint calls, add the `Authorization` HTTP header with a value of `Token `. For example, for a token `1234`, include the header: -`Authorization: Token 1234`. +`Authorization: Bearer 1234` (following OAuth2 RFC 6750) or +`Authorization: Token 1234` (following Django rest framework). ## Scripts diff --git a/dandiapi/api/auth.py b/dandiapi/api/auth.py new file mode 100644 index 000000000..e41c5ad30 --- /dev/null +++ b/dandiapi/api/auth.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from rest_framework.authentication import TokenAuthentication + + +class BearerTokenAuthentication(TokenAuthentication): + """ + To support not only DRF specific but also a standard oauth2 "Bearer" Authorization. + + Supporting both "token" and "Bearer" authorization requests is similar to GitHub behavior: + See https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api?apiVersion=2022-11-28 + + The recipe from https://github.com/encode/django-rest-framework//commit/ffdac0d93619b7ec6039b94ce0e563f0330faeb1 + """ + + keyword = 'Bearer' diff --git a/dandiapi/settings.py b/dandiapi/settings.py index 5550e116e..ed0ac134e 100644 --- a/dandiapi/settings.py +++ b/dandiapi/settings.py @@ -57,6 +57,7 @@ def mutate_configuration(configuration: type[ComposedConfiguration]): # TODO: remove TokenAuthentication, it is only here to support # the setTokenHack login workaround 'rest_framework.authentication.TokenAuthentication', + 'dandiapi.api.auth.BearerTokenAuthentication', ] # Caching