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

Proxy authentication by http header value #696

Closed
max-tet opened this issue Mar 1, 2022 · 13 comments
Closed

Proxy authentication by http header value #696

max-tet opened this issue Mar 1, 2022 · 13 comments
Assignees
Milestone

Comments

@max-tet
Copy link

max-tet commented Mar 1, 2022

Is your feature request related to a problem? Please describe.

When self-hosting multiple applications, you really want to have a single point for user management and authentication. It is annoying to login to each and every app seperately.

A pretty simple way to centralize authentication is achieved by deploying apps behind a reverse proxy, and use proxy auth. The proxy handles authentication in some way and sets http headers containing the username that was successfully logged-in. The apps read the headers and associate incoming requests to that user.

Describe the solution you'd like

The perfect proxy auth feature for me would work like this:

  1. Start convos with additional environment variables:
  • containing the name of the initial admin user (e.g. admin=admin_user)
  • enabling proxy auth (e.g. proxy_auth=true)
  • setting the key of the http header that contains the username (e.g. auth_header=X-Authenticated-User)
  1. Configure the reverse proxy to authenticate incoming requests in any way you like.
  2. Let the reverse proxy set X-Authenticated-User to the authenticated username on every request.
  3. Convos treats the requests as if they belong to the appropriate user session.
  4. Bonus: if Convos does not know the username, it creates a new user with that name.

Describe alternatives you've considered

Other SSO methods like OIDC still require the user to login with each app, even it no credentials are required. It is still an additional step that is unneeded and hurting the user experience.

Additional context

I am using Convos for this product. Since this is a single-user platform, users really should see no login screen at all, not even for SSO.

@jhthorsen jhthorsen added this to the 6.xx milestone Mar 1, 2022
@jhthorsen
Copy link
Collaborator

Interesting problem to solve 👍

I think it would be done with something like this:

CONVOS_PLUGINS=Convos::Plugin::Auth::Header ./script/convos

But the problem is that these "Auth" plugins are only used certain places like in https://github.com/convos-chat/convos/blob/main/lib/Convos/Controller/User.pm#L88, while in this case it would have to be called from https://github.com/convos-chat/convos/blob/main/lib/Convos.pm#L118 to automatically log in the user if the header is seen.

Question: Why do you need to tell Convos who is the initial admin user through an environment variable? Today the first user that register will automatically gain admin rights.

@max-tet
Copy link
Author

max-tet commented Mar 1, 2022

Question: Why do you need to tell Convos who is the initial admin user through an environment variable? Today the first user that register will automatically gain admin rights.

That might be specific to my own use-case. I want a user to install the app (which runs the docker image) and be able to instantly open it and use it without any registration or login or anything. It should feel like installing and starting a smartphone app. The platform I am building is generally a single-user environment, so any up-front user management would feel out of place. Here are more details.

As for your other comments, I cannot speak to that. I don't know the first thing about Perl.

@jhthorsen
Copy link
Collaborator

jhthorsen commented Mar 13, 2022

I've opened a PR for this now. Please have a look at the documentation and let me know what you think: https://github.com/convos-chat/convos/pull/702/files#diff-e0f1e6441c865ff7d4d9919902938773db1e87a5f8b3f915250102c1b85c59a5R49

I would also like to include an example nginx config setup, so it would be excellent if you could provide minimal config. Something like https://convos.chat/doc/reverse-proxy#example-nginx-config

@jhthorsen jhthorsen modified the milestones: 6.xx, 7.00 Mar 13, 2022
@max-tet
Copy link
Author

max-tet commented Mar 13, 2022

As I said, I don't know anything about perl. But I tried to make sense of the code and to my eyes it looks good.
Ufortunately I also don't use nginx and cannot provide a config. Maybe this helps?
I could provide a Traefik config though, if you are interested.

@jhthorsen
Copy link
Collaborator

Traefik config sounds interesting indeed! If you can, I would very much appreciate a guest blog post at https://convos.chat/blog/ about how to set up Convos behind Traefik.

@jhthorsen
Copy link
Collaborator

jhthorsen commented Mar 13, 2022

I'll close this issue now, since it sounds like #702 will get merged. Thank you for your feedback 👍

@max-tet
Copy link
Author

max-tet commented Mar 13, 2022

Hey, that would be nice. I'll certainly consider it! Let's continue this via email.

@toxic0berliner
Copy link

I know this issue is closed but I still wanted to warn, in this example plugin anyone is able to send the X-User header even if they are not authenticated. What I see in other software is that this type of header auth usually also verifies that the request comes from a trusted reverse proxy, so comparing the IP that is sending the request to convos against an IP or range (eg. 172.17. 0.0/16 stored in env var TRUSTED_PROXY) and only reading X-User if the IP matches.
That is to avoid someone bypassing the reverse proxy simply faking the X-User header.

@max-tet
Copy link
Author

max-tet commented Mar 13, 2022

I have never seen the combination with source IP matching being mandatory. But of course you are right. When using proxy auth, you should make sure that the header cannot be faked, i.e. that the proxy always overwrites the header. My understanding is that this is generally understood. Woudn't hurt to perhaps put a red warning box in the documentation.

@toxic0berliner
Copy link

last time I was this was in organizr (https://github.com/causefx/Organizr or more precisely here : https://github.com/rathna023023/grafana2/blob/fc89376977a36876f954ba46bba951137fb55045/pkg/middleware/auth_proxy.go#L124)

That makes sense to me as I always ran things bare-metal and bypassing the proxy was something that need to be actively protected against, but nowerdays that networking is being done in software one can actually setup so it's in fact impossible to bypass the reverse proxy (it's my case with docker) so the need for it is less, but the risk is still there ;)

@jhthorsen
Copy link
Collaborator

@toxic0berliner: Why do you call it an "example plugin"?

Also, about the warning: It's in the documentation, but maybe it needs to be highlighted more? https://convos.chat/doc/Convos/Plugin/Auth/Header#synopsis

I don't mind adding an allow list for where the request comes from though. Feel free to open an issue or a PR if that is something that is needed.

@toxic0berliner
Copy link

My mistake, not an example plugin, just wanted to say "in this plugin".

@jhthorsen
Copy link
Collaborator

The version in 7.00 did not work. Please upgrade to v7.01.

#704 (comment)

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

No branches or pull requests

3 participants