#2198 closed defect (invalid)
Authorization from auth_request
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | major | Milestone: | |
Component: | nginx-core | Version: | |
Keywords: | Cc: | ||
uname -a: | Linux vigrid-gns3 5.4.0-74-generic #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux | ||
nginx -V: |
nginx version: nginx/1.21.0
built by gcc 9.3.0 (Ubuntu 9.3.0-10ubuntu2) built with OpenSSL 1.1.1f 31 Mar 2020 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.21.0/debian/debuild-base/nginx-1.21.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' |
Description
Hello,
I got a situation that cant be explained.
On 2 servers exactly the same, both are:
- with Ubuntu 20.04.2LTS from scratch
- NGinx 1.21.0 from apt after added your repo
- Same PHP-FPM (7.4) configuration & modules
- Same NGinx configs (main & auth server)
- Same permissions/ownership at all levels (sock, config files etc).
Despite this, one auth_request sent to the backoffice server (that updates the Authorization header) works but the other fails.
FAILS means the Authorization header is changed at the back office auth site, but the master server does not receive the header updated, still keeping and sending the old one from client to the proxied server.
I tried with more_set_headers as well, no change.
The dump & configs details you have are EXACTLY the same on both servers, IP included...
I faced this already once, but NGinx was 1.14. Once updated to 1.19.0, the issues was solved, so I consider it was a NGinx version issue. Here .21 (>.19) should be ok then...
Thanks for your feedback
Brgrds
CALLING CONFIG:
location /subdir
{
auth_request /auth;
auth_request_set $auth_status $upstream_status;
proxy_pass http://172.29.0.254:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location = /auth
{
internal;
proxy_pass http://localhost:8001;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
## Back office Authenticating site:
server {
listen 127.0.0.1:8001;
server_name localhost;
access_log /var/log/nginx/vigrid_auth-access.log;
error_log /var/log/nginx/vigrid_auth-error.log;
root /home/gns3/vigrid/www/auth;
index vigrid-auth.php;
# hide version
server_tokens off;
location ~ /\.ht {
deny all;
}
location /
{
# cleaning
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { log_not_found off; }
location ~ \.css { add_header Content-Type text/css; }
location ~ \.js { add_header Content-Type application/x-javascript; }
location ~ \.eot { add_header Content-Type application/vnd.ms-fontobject; }
location ~ \.woff { add_header Content-Type font/woff; }
location ~* \.(htm|html|php)$
{
try_files $uri =404;
fastcgi_split_path_info (.+\.php)(/.+)$;
fastcgi_index vigrid-auth.php;
fastcgi_pass_header Authorization;
include /etc/nginx/fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /(images|javascript|js|css|flash|media|static|font)/ {
expires 7d;
}
location ~ /\.ht {
deny all;
}
try_files $uri $uri/ /vigrid-auth.php?$args;
}
}
Change History (6)
comment:1 by , 4 years ago
follow-up: 4 comment:2 by , 4 years ago
FAILS means the Authorization header is changed at the back office auth site, but the master server does not receive the header updated, still keeping and sending the old one from client to the proxied server.
Could you please clarify a bit more what do you mean here?
Note that nginx never changes the Authorization
request header, and it is not expected to (unless you've explicitly configured something like proxy_set_header Authorization ...;
). The only thing that the auth_request is expected to do is explicitly documented: when access is denied with the 401 error code, it returns the WWW-Authenticate
response header to the client, so the client can provide acceptable authentication information via the Authorization
request header in the next request.
Overall, this doesn't look like a bug in nginx, but rather a misbehaviour of the code which handles authorization subrequests.
comment:3 by , 4 years ago
Hello,
Since mainline might not be 'stable' version, retested with 1.20.0, same thing.
Tested authorization using new config, NGinx behaves better but is missing many URLs it received.
New config (where it changed):
location /subdir
{
auth_request /auth;
auth_request_set $auth_status $upstream_status;
added -> auth_request_set $auth_header $upstream_http_authorization;
proxy_pass http://172.29.0.254:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
added -> proxy_set_header Authorization $auth_header;
}
comment:4 by , 4 years ago
Hello Maxim,
Replying to Maxim Dounin:
Could you please clarify a bit more what do you mean here?
Note that nginx never changes the
Authorization
request header, and it is not expected to (unless you've explicitly configured something likeproxy_set_header Authorization ...;
). The only thing that the auth_request is expected to do is explicitly documented: when access is denied with the 401 error code, it returns theWWW-Authenticate
response header to the client, so the client can provide acceptable authentication information via theAuthorization
request header in the next request.
Overall, this doesn't look like a bug in nginx, but rather a misbehaviour of the code which handles authorization subrequests.
Let me illustrate with an example. CURL calls for this URL, adding web auth:
curl -kv -u vigrid:vigrid -A "Client" -X GET https://localhost/subdir/version
NGinx receives this request, because of /subdir, it is specically handled by a location.
This location includes an auth_request and so it is sent to the back office auth server.
This auth server (port 8001) receives and validates access.
IT ALSO CHANGES the Authorization header to put another auth (the credentials of the real final server are unique, so the auth part also manages this).
Normally, this updated header is sent back to the 'calling NGinx location' and then proxy does its job, sending the same URL (upgrading it to websocket) with the new Authorization header.
On a fresh Ubuntu 20.04.2LTS, it fails. On the same Ubuntu 20.04.2 LTS but olrder, same software versions etc (tested nginx/PHP Versions a config files, all dev pages etc, diff = zero with failing config), it works.
Since this is NGinx internal to me, I dont except Ubuntu to interfere. Since NGinx/PHP versions are exactly the same as well as config files, I dont expect a different behavior.
That is my point...
follow-up: 6 comment:5 by , 4 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
IT ALSO CHANGES the Authorization header to put another auth (the credentials of the real final server are unique, so the auth part also manages this).
As explained above, this is not how it is expected to work. The Authorization
header i the request header, and it is expected to come from the client. If you want to change it to something different in proxied requests, you have to explicitly configure nginx to do so by using appropriate proxy_set_header
.
Normally, this updated header is sent back to the 'calling NGinx location' and then proxy does its job, sending the same URL (upgrading it to websocket) with the new Authorization header.
Again, this is not what expected to happen. If this indeed happens on some of your servers, this probably means that you are running locally modified nginx which behaves differently from what it is expected to do. But most likely it happen to work for some other reason. You may want to check what actually happens on the wire - notably, what's in the headers from the client to nginx, from auth backend to nginx, and from nginx to the real backend.
Either way, thank you for the details. Certainly this does not look like a bug in nginx, as nginx is simply not expected to do what you think it should, so closing this. If you need help with configuring nginx, consider using support options available.
comment:6 by , 4 years ago
Replying to Maxim Dounin:
IT ALSO CHANGES the Authorization header to put another auth (the credentials of the real final server are unique, so the auth part also manages this).
As explained above, this is not how it is expected to work. The
Authorization
header i the request header, and it is expected to come from the client. If you want to change it to something different in proxied requests, you have to explicitly configure nginx to do so by using appropriateproxy_set_header
.
Ok, no problemo, then there is a "bug that is a feature" :-)
I mean it happens in multiple of my hosts, despite it should not.
Normally, this updated header is sent back to the 'calling NGinx location' and then proxy does its job, sending the same URL (upgrading it to websocket) with the new Authorization header.
Again, this is not what expected to happen. If this indeed happens on some of your servers, this probably means that you are running locally modified nginx which behaves differently from what it is expected to do. But most likely it happen to work for some other reason. You may want to check what actually happens on the wire - notably, what's in the headers from the client to nginx, from auth backend to nginx, and from nginx to the real backend.
Either way, thank you for the details. Certainly this does not look like a bug in nginx, as nginx is simply not expected to do what you think it should, so closing this. If you need help with configuring nginx, consider using support options available.
Since that, the location became:
location /subdir
{
auth_request /auth;
auth_request_set $auth_status $upstream_status;
auth_request_set $auth_header $upstream_http_authorization;
proxy_pass http://172.29.0.254:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header Authorization $auth_header;
}
That is supposed to get the Authorization header from the /auth page.
Since that, as I indicated earlier, it seems to be the appropriate way but...it works more or less. In other terms, it does not work at all times as it should be.
Keep digging these differences...
"I faced this already once, but NGinx was 1.14. Once updated to 1.19.0, the issues was solved, so I consider it was a NGinx version issue. Here .21 (>.19) should be ok then..."
I face it another time of course :-)