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

[server] FR: Proxy authentication by http header value #3

Closed
max-tet opened this issue Oct 4, 2022 · 15 comments · Fixed by #11
Closed

[server] FR: Proxy authentication by http header value #3

max-tet opened this issue Oct 4, 2022 · 15 comments · Fixed by #11
Assignees
Labels
enhancement New feature or request hacktoberfest
Milestone

Comments

@max-tet
Copy link

max-tet commented Oct 4, 2022

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.

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

  1. Start the app 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. The app treats the requests as if they belong to the appropriate user session.
  4. Bonus: if the app does not know the username, it creates a new user with that name.

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 the app for this product. Since this is a single-user platform, users really should see no login screen at all, not even for SSO.

@dorianim
Copy link
Owner

dorianim commented Oct 4, 2022

Yep, I also run authentik for sso. Hkwever, I'd rather try to implement oidc, as it is easier to mix sso an "guest" users like that. With header authentication, every user would have to be registered in the sso provider.
But I'm not saying I won't implement header auth at all, since it is super simple.

@max-tet
Copy link
Author

max-tet commented Oct 4, 2022

Yes, I agree, both is useful. Header auth is just a quick win.

@dorianim dorianim added the enhancement New feature or request label Oct 4, 2022
@dorianim dorianim self-assigned this Oct 4, 2022
@dorianim dorianim added this to the v1.3.0 milestone Oct 4, 2022
@dorianim dorianim changed the title Feature Request: Proxy authentication by http header value [server] FR: Proxy authentication by http header value Oct 4, 2022
@dorianim
Copy link
Owner

dorianim commented Oct 4, 2022

My plan is this now:
Configure like this:

MONEYBALANCER_AUTH_PROXY_ENABLED=true
MONEYBALANCER_AUTH_PROXY_HEADERS_USERNAME=X-authentik-username
MONEYBALANCER_AUTH_PROXY_HEADERS_NICKNAME=X-authentik-name

This would then enable proxy authentication and configure the respective headers. It will also create users in case they do not exist yet.
The nickname header is optional, it will use the username if not configured.

Is that what you wished for @max-tet ?

@max-tet
Copy link
Author

max-tet commented Oct 5, 2022

Yes, pretty much, thank you!

I am just confused about the nickname. By putting it in a header you are setting yourself up for weird corner cases. E.g. how to handle a request containing a valid username but the wrong nickname. Or without nickname?

I would decide which name is the unique identifier, probably username. This should be the only one needed in the header. When auto-creating a user, just always fill the nickname with the username and let them change it later in the UI.

That removes the MONEYBALANCER_AUTH_PROXY_HEADERS_NICKNAME header and makes it all a bit simpler.

@dorianim
Copy link
Owner

dorianim commented Oct 5, 2022

Authentik provides the display name of the user in the X-authentik-name header, see here.

how to handle a request containing a valid username but the wrong nickname. Or without nickname?

If the nickname is wrong or missing, even though it is configured, that is the fault of the authentication provider / the user who configured it. If you don't need it, just don't configure it :)
The username is always the unique identifier, the nickname (+ possibly more attributes in the future, like email) is updated according to the header.

@max-tet
Copy link
Author

max-tet commented Oct 5, 2022

Ok got it. So you can change details about a user with the headers you are sending in the request. Never seen it like that before, but why not. I am not sure if there are some security implications here though.

Well anyway, that feature would be totally fine for my needs. 👍

@dorianim dorianim mentioned this issue Oct 5, 2022
3 tasks
dorianim added a commit that referenced this issue Oct 7, 2022
Fixes #3 

Will be implemented like this:
- The proxy authentication provider has to be configured to protect
these routes:
  - `/api/v1/auth/proxy`
  - `/#/login/proxy`
  - Everything else is protected by the regular JWT authentication
- The client will redirect to `/#/login/proxy` to trigger the login
- The client will get a JWT token by sending an empty POST-request to
`/api/v1/auth/proxy`.
- This allows an instance to use not only proxy authentication but also
another one like local or oidc
@dorianim
Copy link
Owner

dorianim commented Oct 7, 2022

@max-tet this should be done :)
There will be a preview image ghcr.io/dorianim/money-balancer:preview in a few minutes. Would be great if you could test with that and let me know if it works.

@max-tet
Copy link
Author

max-tet commented Oct 7, 2022

Can't get it to work tbh. I'm not sure if I do something wrong? I start it with these environment variables:

- MONEYBALANCER_AUTH_PROXY_ENABLED=true
- MONEYBALANCER_AUTH_PROXY_HEADERS_USERNAME=X-Ptl-Authenticated-User
- MONEYBALANCER_JWT_SECRET=foo

Requests have the header X-Ptl-Authenticated-User filled with the username. I am not using the nickname.

When I access the app, I am redirected to the login view.

@dorianim
Copy link
Owner

dorianim commented Oct 7, 2022

The problem ist probably the casing in the headers. Please make them all lowercase.
I just pushed an update to fix this in #12, but it'll take a few minutes to build.

@max-tet
Copy link
Author

max-tet commented Oct 7, 2022

Changed the var to MONEYBALANCER_AUTH_PROXY_HEADERS_USERNAME=x-ptl-authenticated-user but still, I am redirected to login. That doesn't seem to be the problem.

@dorianim
Copy link
Owner

dorianim commented Oct 7, 2022

Does the button "login using sso" appear on the login page?
image

@max-tet
Copy link
Author

max-tet commented Oct 7, 2022

Yes it is there. If i click it, there is a screen called "Proxy login ..." with an endless spinner.
I can see a POST to /api/v1/auth/proxy that returns 500.

Edit: There is also this log entry:

thread 'rocket-worker-thread' panicked at 'called `Option::unwrap()` on a `None` value', src/services/authentication.rs:79:69

@dorianim
Copy link
Owner

dorianim commented Oct 7, 2022

Whoops, my bad! Just pushed a fix in 05dcea6
Again, in about 15 Minutes the preview image will be ready :)
By the way, if you set MONEYBALANCER_AUTH_LOCAL_ENABLED=false, the redirect will occur automatically with no user interaction needed.

@dorianim
Copy link
Owner

dorianim commented Oct 7, 2022

I can't find any more problems now. Please try again with the newest image :)

@max-tet
Copy link
Author

max-tet commented Oct 8, 2022

Just tried it, works great! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request hacktoberfest
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants