nginx-proxy-manager icon indicating copy to clipboard operation
nginx-proxy-manager copied to clipboard

FEAT: Open ID Cconnect authentication

Open marekful opened this issue 3 years ago • 47 comments

FEAT: Add Open ID Connect authentication method (SSO)

Resolves: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/2562 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/69 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/437 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1624

  • add oidc-config setting allowing an admin user to configure parameters
  • modify login page to show another button when oidc is configured
  • add dependency openid-client v5.4.0
  • add backend route to process "OAuth2 Authorization Code" flow initialisation
  • add backend route to process callback of above flow
  • sign in the authenticated user with internal jwt token if internal user with email matching the one retrieved from oauth claims exists

Note: Only Open ID Connect Discovery is supported which most modern Identity Providers offer.

Tested with Authentik 2023.2.2 and Keycloak 18.0.2

Screenshot 2023-02-24 at 22 55 10 Screenshot 2023-02-24 at 22 55 34 Screenshot 2023-02-24 at 22 55 47

marekful avatar Feb 24 '23 21:02 marekful

This is an automated message from CI:

Docker Image for build 1 is available on DockerHub as jc21/nginx-proxy-manager:github-pr-2630

Note: ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.

This is an automated message from CI:

Docker Image for build 2 is available on DockerHub as jc21/nginx-proxy-manager:github-pr-2630

Note: ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.

22:45:03  $ /app/node_modules/.bin/eslint .
22:45:03  
22:45:03  /app/setup.js
22:45:03    158:1  error  Expected indentation of 1 tab but found 2   indent
22:45:03    159:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03    160:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03    161:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03    162:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03    163:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03    164:1  error  Expected indentation of 3 tabs but found 4  indent
22:45:03    165:1  error  Expected indentation of 4 tabs but found 5  indent
22:45:03    166:1  error  Expected indentation of 5 tabs but found 6  indent
22:45:03    167:1  error  Expected indentation of 5 tabs but found 6  indent
22:45:03    168:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    169:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    170:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    171:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    172:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    173:1  error  Expected indentation of 5 tabs but found 6  indent
22:45:03    174:1  error  Expected indentation of 5 tabs but found 6  indent
22:45:03    175:1  error  Expected indentation of 6 tabs but found 7  indent
22:45:03    176:1  error  Expected indentation of 5 tabs but found 6  indent
22:45:03    177:1  error  Expected indentation of 3 tabs but found 4  indent
22:45:03    178:1  error  Expected indentation of 3 tabs but found 4  indent
22:45:03    179:1  error  Expected indentation of 4 tabs but found 5  indent
22:45:03    180:1  error  Expected indentation of 3 tabs but found 4  indent
22:45:03    181:1  error  Expected indentation of 2 tabs but found 3  indent
22:45:03  
22:45:03  ✖ 24 problems (24 errors, 0 warnings)

jc21 avatar Mar 07 '23 12:03 jc21

Apologies.

marekful avatar Mar 09 '23 21:03 marekful

This is an automated message from CI:

Docker Image for build 7 is available on DockerHub as jc21/nginx-proxy-manager:github-pr-2630

Note: ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.

More of a general question with this PR. is it possible to provide the OIDC parameters using env vars or a config file to the docker container? Reason being, if you misconfigure something and it locks you out, recovery can become very painful. (atleast in my experience with other applications)

rijnhard avatar Apr 02 '23 14:04 rijnhard

A question: This is only meant to allow login to nginx-proxy-manager admin UI, right? Or would this allow configuring access to proxied sites?

krombel avatar Apr 02 '23 19:04 krombel

Hey @rijnhard,

The risk of locking yourself out is the same with or without OIDC being involved because the default (built-in) login option is never hidden or becomes unavailable. If OIDC is misconfigured, you can login locally as admin and fix it.

Keep in mind that, as described above, a local user must exist in order to sign in to NPM with OIDC. That local user has a password in NPM that is independent of any remote identity. If you lose access to the configured OIDC identity, you can still sign in to NPM with the users's local password.

marekful avatar Apr 07 '23 13:04 marekful

Hi @krombel,

Yes, that's correct. Following a successful OIDC authentication, you are practically signed in to NPM with the local user, only we didn't ask for the password (because the IdP already did). So everything stays the same as you were signed in using the same user's password for NPM.

marekful avatar Apr 07 '23 13:04 marekful

This is just what im looking for at ensuring all my home services are SSO compatible! Would definitely love to see this in a release soon. (also using authentik as well).

aaronnad avatar Apr 12 '23 23:04 aaronnad

Great PR! 👍

  • SSO users dashboard metrics do not seem to populate correctly. i.e. 0 Proxy Hosts, 0 Redirection Hosts etc. (there are in fact entries that correctly display when authenticated as a local-only user.

mwstamant avatar May 09 '23 22:05 mwstamant

Following @mwstamant's comment I have also had a positive experience testing this new feature. The dashboard metrics are also an issue I am seeing. The OIDC was very simple to configure with my lab Authentik setup. I was able to direct Authentic to open http://domain.void/api/oidc/ to bypass the human interaction step to authenticate.

TechWolfNZ avatar May 20 '23 11:05 TechWolfNZ

Thanks for implementing this. I am using the docker image "jc21/nginx-proxy-manager:latest". Do I need to switch to "jc21/nginx-proxy-manager:github-pr-2630" or can I activate "oidc-config" somewhere in the settings or as an environment variable?

thimplicity avatar Jun 23 '23 00:06 thimplicity

Hello! Any idea what work is left on this?

Shocktrooper avatar Aug 02 '23 15:08 Shocktrooper

+1

Hadatko avatar Aug 25 '23 06:08 Hadatko

Bump for merge conflict resolution

Shocktrooper avatar Sep 13 '23 16:09 Shocktrooper

+1 NPM, is the only service I'm using and doesn't have OIDC.

mrhackcz avatar Oct 02 '23 19:10 mrhackcz

bump for this, also willing to test. I am currently about 8 hours into merging nginx / lua / open resty for the exact same feature. I would be using Jumpcloud though as the goal is to eliminate applications and jumpcloud cuts out a very large portion of them for my personal network.

This is what I am would like to get integrated, as OIDC Discovery has a few vulnerabilities, Oauth 2.0 is much better, and doing it this way allows for the token validation to be on the NGINX side. THIS MEANS SSO! Performing validation at each backend service or application results in a lot of duplicate code and unnecessary processing. Various error conditions and edge cases need to be accounted for, and doing so in each backend service is a recipe for inconsistency in implementation and consequently an unpredictable user experience.

The flow would for a complete system, you click a link to one of your apps, it redirects you to your OIDC, in my case Jumpcloud, you sign in (jumpcloud also has full integration now aka passwordless, I use facial recognition), and it would sign you in on ALL of your apps, aka SSO. I already had it working with Cloudflare tunnels, but I am moving away from having my data unencrypted in random places.

I intend to nail down exactly what lua scripts are needed for this to operate bare bones, but I see no reason why this could not be integrated here.

acester822 avatar Oct 09 '23 23:10 acester822

For those following this, I actually got it to work right out of the box as configured lol. I basically evoked the lua scripts from a default.conf in NPM and from there I basically tweaked, added, and manipulated a configuration that automatically adds my OIDC aka Jumpcloud without me having to touch it on the NGINX side. I do have to add it to my OIDC integration on the other side, which is super easy. Now all my apps are secure again without cloudflare and with facial/fingerprint recognition!

acester822 avatar Oct 10 '23 20:10 acester822

+1 I am also interested in this. I've pulled it down and tested it and everything seems to work, but it's been 8 months and the branch is starting to fall behind. Is it possible to resolve the conflicts add the NPM owner as a reviewer?

isaiah-v avatar Oct 12 '23 16:10 isaiah-v

+1 I am also interested in this. I've pulled it down and tested it and everything seems to work, but it's been 8 months and the branch is starting to fall behind. Is it possible to resolve the conflicts add the NPM owner as a reviewer?

Ye, it is a little buggy the way that I implemented it, but I am sure it is because of crappy lua configuring, I bet it would be easy to implement properly, basically all I did to get it to work was figure out the right places for the code and since this is based off of openresty it worked,

I made a default.conf and added this;

lua_package_path` '~/lua/?.lua;;';


  lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
  lua_ssl_verify_depth 5;

  # cache for discovery metadata documents
  lua_shared_dict discovery 1m;
  # cache for JWKs
  lua_shared_dict jwks 1m;

Then in NPM, added this into the custom locations section,

	access_by_lua_block {

          local opts = {
             redirect_uri_path = "/redirect_uri",
             accept_none_alg = true,
             redirect_uri_scheme = "https",
             discovery = "https://oauth.id.jumpcloud.com/.well-known/openid-configuration",
             client_id = "get your own",
             client_secret = "nope",

          }

          -- call authenticate for OpenID Connect user authentication
          local res, err = require("resty.openidc").authenticate(opts)

          if err then
            ngx.status = 500
            ngx.say(err)
            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
          end

          ngx.req.set_header("X-USER", res.id_token.sub)

Doing it this way, I can get it to work on a per port basis so things like Nextcloud with native SAML support work great, but all the other random ports I want to protect I can. The issue is on first page load it often times gives me an error, but on reload it works fine. Obviously this would not be the most elegant solution, but would be pretty simple to add in it seems. Hell you could even do a simple mode, which is basically what it is now, or switch to advanced mode where it would show the additional options.

acester822 avatar Oct 12 '23 17:10 acester822

@jc21 what are your thoughts?

acester822 avatar Oct 12 '23 17:10 acester822

is this activated? or can I activate in my instance of NPM?

SecureCPU avatar Nov 16 '23 20:11 SecureCPU

is this activated? or can I activate in my instance of NPM?

kind of but it is buggy and did not work well, I ended up going with traefik instead

acester822 avatar Nov 17 '23 00:11 acester822

I'm super interested on this feature. Is there any plan to merge it soon?

jcebrianalonso avatar Feb 01 '24 20:02 jcebrianalonso

@marekful Can you solve the merge conflicts?

Shocktrooper avatar Feb 07 '24 19:02 Shocktrooper

@marekful Can you solve the merge conflicts?

alexsalex avatar Feb 10 '24 03:02 alexsalex

Please please please resolve the conflict and merge it,please!

alexsalex avatar Feb 10 '24 03:02 alexsalex

After testing, I have some issues. I can't open the settings window in Safari browser. I can't log out in any browser.

Clear cache solve the issue)

Otherwise, everything works fine! Love it!!!

alexsalex avatar Feb 10 '24 04:02 alexsalex

please @marekful solve the conflicts and merge. This would be a great addition to NGINX Proxy Manager!!

jcebrianalonso avatar Feb 23 '24 12:02 jcebrianalonso