User tests: Successful: Unsuccessful:
This change makes the authorization header case insensitive.
In the IETF standsrds docs at https://tools.ietf.org/html/rfc2616#section-4.2 it states that "Field names are case-insensitive."
See issue...
Auth headers in Joomla 4 API should maybe be case insensitive #30871
This means, both...
curl --location --request GET 'http://MYDOMAIN//api/index.php/v1/content/article' --header 'Authorization: Bearer MY_API_TOKEN_HERE'
...and...
curl --location --request GET 'http://MYDOMAIN/api/index.php/v1/content/article' --header 'authorization: Bearer MY_API_TOKEN_HERE'
...both work.
Pull Request for Issue # .
This change makes the authorization header case insensitive in the API when using Bearer token.
Set up a test site at http://localhost/joomla/joomla_4_beta_4
Get a Joomla API Token, from, for example https://localhost/joomla/joomla_4_beta_4/administrator/index.php?option=com_users&view=users
Do an uppercase test...
curl --location --request GET 'http://MYDOMAIN//api/index.php/v1/content/article' --header 'Authorization: Bearer MY_API_TOKEN_HERE'
Do a lowercases test...
curl --location --request GET 'http://MYDOMAIN/api/index.php/v1/content/article' --header 'authorization: Bearer MY_API_TOKEN_HERE'
Uppercase test gets a good json response of article content
Lowercase gets an gets a 406 response
Uppercase test gets a good json response of article content
Lowercase test gets a good json response of article content
None
Status | New | ⇒ | Pending |
Category | ⇒ | Front End Plugins |
Not really related to the PR directly, but perhaps a comment for future google-ers.
In the most popular flutter http package, http.dart
, see https://pub.dev/packages/http the headers are always passed in lowercase. So before this change, any flutter API client code using http.dart
was not able to use the Joomla 4 API bearer API token option.
This is how I came across this, working on a basic example Flutter App at https://github.com/AndyGaskell/joomla4api_basic_flutter_app
There is a problem! For me the curl test works without the patch with both upper and lower case Authentication. Looking at the code, on line 91, $authHeader is not empty and so the case conversion is never called. But then on line 103 a header is compared with 'Bearer'.
Can you be a bit more specific? That was not changed by that patch so should be an issue before too right?
Ah you mean line 103 that was not shown to my diff ;) https://github.com/joomla/joomla-cms/pull/30882/files#diff-cca9165cd01f0d3d0fa6b27485dab967L103
Can you take a look into that @AndyGaskell ?
Thanks @zero-24 and @ceford for reviewing the PR.
I'll look into this today.
@ceford could you please add some details of what web server set-up you have? I would guess $authHeader
is getting set on line 87 when you run this, rather than on line 94 when I run this. I'm thinking perhaps this bug is only exhibited when authHeader
is empty and apache2handler
is used. Perhaps $this->app->input->server->get('HTTP_AUTHORIZATION', '', 'string');
gets the header values in a case insensitive way, so side-steps the problem.
My web-server set-up is...
I'm just reading through the symphony issue mentioned in the code comment on line 90...
// Apache specific fixes. See https://github.com/symfony/symfony/issues/19693
I am working on a Macbook Pro. My settings:
PHP Version: 7.4.2
Web Server: Apache/2.4.41 (Unix) PHP/7.4.2
WebServer to PHP Interface: apache2handler
Joomla! Version: Joomla! 4.0.0-beta5-dev Development [ Mañana ] 15-September-2020 19:15 GMT
Is that enough?
Thanks for the info @ceford that's really useful. It's really pretty much the same as what I'm using, so my theory about variation in behaviour being due to some difference in web server settings or platform are probably off the mark.
I'll try some experiments to recreate this in other ways, to see if I can get figure out what's going on.
Hope it's less rainy in Edinburgh than here in Aberdeen today :)
I tried it on my laptop here, to test on a different system, and it behaved in the same way as my other tests.
My laptop has...
I tried to see if there was any difference in header case implementation in OSX Apache v Linux Apache, but I found no docs or discussion that indicated any difference.
I'll check with 4.0.0-beta5-dev, perhaps there is a small difference between that and 4.0.0-beta4 that I've been using.
@AndyGaskell i would say we have to lovercase Authorization
when using the HTTP_AUTHORIZATION header too.
As it seems @ceford uses the HTTP_AUTHORIZATION header?
@ceford can you show us the command you are using?
I just tried it with the latest code from master and the result was the same as previous tests. To do this I installed 4.0.0-beta4 Beta then over-wrote the files with 4.0-dev from git.
@zero-24 Thanks for your thoughts, I don't really fully understand what happens, but I was thinking that...
$authHeader = $this->app->input->server->get('HTTP_AUTHORIZATION', '', 'string');
...gets the value regardless of case. In my tests, authHeader
is always empty, after the call on line 87, so it goes into the if (empty($authHeader)
logic on line 91.
I'm wasn't very familiar with the HTTP_AUTHORIZATION
element of the _SERVER
array, it is not mentioned on https://www.php.net/manual/en/reserved.variables.server.php but there is a mention of it on https://tools.ietf.org/html/rfc3875 . I was wondering if this logic was used with a FastCGI web server implementation, and not in Apache. There was some discussion to this effect on symfony/symfony#19693
These are the two commands I used for testing, with the token obscured:
ceford@cliff ~ % curl --location --request GET 'http://localhost/j4b4/api/index.php/v1/content/article' --header 'authorization: Bearer xxx'
ceford@cliff ~ % curl --location --request GET 'http://localhost/j4b4/api/index.php/v1/content/article' --header 'Authorization: Bearer xxx'
Also I checked the content of $authheader and found it the same in both cases:
Line 89 $authheader: 'Bearer xxx'
If I change authorization to xuthorization then $authheader is empty and I get a forbidden message.
I searched for HTTP_AUTHORIZATION and found this in .htaccess:
# PHP FastCGI fix for HTTP Authorization, required for the API application
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
There is also a mention in libraries/vendor/laminas/laminas-diactoros/src/function/normalize-server.php - I have no idea what that is used for.
Hi @ceford
Thanks for the extra details, I think that makes sense now. I guess the difference in what we're seeing is probably because you have the .htaccess
in place, where as I just have it still called htaccess.txt
.
If you rename .htaccess
to htaccess.txt
then run the the lowercase curl
command, what do you get back?
Looking in git, that...
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
...line has been in the htaccess file's core SEF Section for over 10 years.
Just checked this here, if I rename my htaccess.txt
to .htaccess
then the code reads the header in...
$authHeader = $this->app->input->server->get('HTTP_AUTHORIZATION', '', 'string');
...in uppercase and lowercase.
So I guess the...
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
...line in htaccess casts the header variable into the $_SERVER
super global variable in a case-insensitive way.
So, my feeling is that this is a bug, but only one you see if you don't rename the htaccess file.
I have tested this item
With .htaccess out of the way I found my code had not cleanly removed the patch. With the original restored and the patch applied I can confirm that both Authorization and authorization now work.
I have tested this item
I think the differences in the test results come from the operating systems. Linux is a case sensitive system, while Windows and MacOS are case insensitive by default.
Thanks merging.
Status | Pending | ⇒ | Fixed in Code Base |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2020-10-17 13:55:00 |
Closed_By | ⇒ | zero-24 | |
Labels |
Added:
?
|
I checked if it effects, Basic Auth in the same way...
https://github.com/joomla/joomla-cms/blob/4.0-dev/plugins/api-authentication/basic/basic.php
...but it does not, so that's good.