Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AUTH_REMOTE_USER reads REMOTE_USER variable instead of HTTP_REMOTE_USER #1764

Open
sc-anssi opened this issue Dec 27, 2021 · 5 comments
Open
Labels

Comments

@sc-anssi
Copy link

Environment

Flask-Appbuilder version: 3.4.1

pip freeze output:

apispec==3.3.2
attrs==21.2.0
Babel==2.9.1
click==7.1.2
colorama==0.4.4
defusedxml==0.7.1
dnspython==2.1.0
email-validator==1.1.3
Flask==1.1.4
Flask-AppBuilder==3.4.1
Flask-Babel==2.0.0
Flask-JWT-Extended==3.25.1
Flask-Login==0.4.1
Flask-OpenID==1.3.0
Flask-SQLAlchemy==2.5.1
Flask-WTF==0.14.3
idna==3.3
itsdangerous==1.1.0
Jinja2==2.11.3
jsonschema==3.2.0
MarkupSafe==2.0.1
marshmallow==3.14.1
marshmallow-enum==1.5.1
marshmallow-sqlalchemy==0.26.1
prison==0.2.1
PyJWT==1.7.1
pyrsistent==0.18.0
python-dateutil==2.8.2
python3-openid==3.2.0
pytz==2021.3
PyYAML==6.0
six==1.16.0
SQLAlchemy==1.3.24
SQLAlchemy-Utils==0.38.1
Werkzeug==1.0.1
WTForms==2.3.3

Describe the expected results

When using FAB with AUTH_TYPE = AUTH_REMOTE_USER behind a reverse proxy which sets the request header REMOTE_USER, FAB should authenticate that user when trying to login

Describe the actual results

Authentication fails with message Invalid login. Please try again. when clicking "login" link.

Steps to reproduce

  1. Setup the base skeleton app
  2. Modify config.py to set AUTH_TYPE = AUTH_REMOTE_USER
  3. Setup a reverse proxy in front of the app setting the request header REMOTE_USER to "Admin" (the following example is for Apache HTTPD):
        ProxyRequests Off
        ProxyPass / "http://localhost:5000/"
        ProxyPassReverse / "http://localhost:5000/"
        RequestHeader set REMOTE_USER Admin
  1. Restart reverse proxy and start the app
  2. Try to login and fail with message Invalid login. Please try again.

Potential lead

I believe CGI uses HTTP request headers as environment variable by prefixing them with HTTP_ (https://www.ietf.org/rfc/rfc3875, section 4.1.18). However FAB reads REMOTE_USER in flask_appbuilder/security/views.py.

Patching the code as follow seems to fix the problem:

--- a/flask_appbuilder/security/views.py
+++ b/flask_appbuilder/security/views.py
@@ -715,7 +715,7 @@ class AuthRemoteUserView(AuthView):
 
     @expose("/login/")
     def login(self) -> WerkzeugResponse:
-        username = request.environ.get("REMOTE_USER")
+        username = request.environ.get("HTTP_REMOTE_USER")
         if g.user is not None and g.user.is_authenticated:
             return redirect(self.appbuilder.get_url_for_index)
         if username:
@dpgaspar
Copy link
Owner

dpgaspar commented Jan 4, 2022

This is intended to be used with IIS on an internal network by setting windows authentication enabled and anonymous disabled.

@sc-anssi
Copy link
Author

sc-anssi commented Jan 5, 2022

Hi,

The documentation mentions Apache and Nginx but I've not seen any reference to IIS in /docs/security.rst. But I don't think the webserver acting as reverse proxy is responsible for the issue at hand. If you tcpdump the traffic between the reverse proxy and the Flask webserver you can see the header is indeed REMOTE_USER, so the conversion of HTTP headers to environment variables by prefixing HTTP_ is done by Flask/Werkzeug I believe.

That's why I believe FAB should either read HTTP_REMOTE_USER from request.environ or read Remote-User from request.headers (the first option seems to be the easiest one as we don't have to worry about the case or the mix of dashes and underscores in headers)

What do you think ?
Regards

@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Feel free to reopen it if it's still relevant to you. Thank you

@stale stale bot added the stale label Apr 16, 2022
@stale stale bot closed this as completed Apr 29, 2022
@sc-anssi
Copy link
Author

Hi,
This issue is still relevant.
@dpgaspar what do you think of the suggested fix ?
Regards

@slmg
Copy link

slmg commented Apr 9, 2023

I am attempting to run an authenticating reverse proxy in front of a FAB app, and I am faced with this exact issue. Passing REMOTE_USER in the request headers from the proxy results to HTTP_REMOTE_USER in the request.environ object of the FAB web-server.

As suggested by @sc-anssi, a very simple change would enable authentication to be offloaded. We could check HTTP_REMOTE_USER exists in request.environ in addition to REMOTE_USER (to preserve compatibility for anyone relying on REMOTE_USER)?

Could this issue please be re-open @dpgaspar?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants