babelouest / glewlwyd

Experimental Single Sign On server, OAuth2, Openid Connect, multiple factor authentication with, HOTP/TOTP, FIDO2, TLS Certificates, etc. extensible via plugins
https://babelouest.github.io/glewlwyd
Other
430 stars 80 forks source link

Nginx proxy config in a folder #152

Closed RNCTX closed 4 years ago

RNCTX commented 4 years ago

I'd like to use this app on a shared subdomain with other apps, each residing in a folder that Nginx proxies to based on the directory in the URL.

I've tried the following:

Nginx config:

 # Glewlwyd
        location ~/authsrv(.*?)$ {
            proxy_set_header Authorization $http_authorization;
            proxy_set_header Host $host;
            proxy_pass_header  Authorization;
            proxy_pass         http://127.0.0.1:4593$1;
        }

Glewlwyd.conf:

# port to open for remote commands
port=4593

# bind to IPV4 address
bind_address="127.0.0.1"

# external url to access to this instance
external_url="https://site.url"

# login url relative to external url
login_url="login.html"

# url prefix
api_prefix="api"

# path to static files for /webapp url
static_files_path="/usr/share/glewlwyd/webapp/"

webapp/config.json:

{
  "GlewlwydUrl": "https://site.url/authsrv/",
  "ProfileUrl": "profile.html",
  "AdminUrl": "index.html",
  "LoginUrl": "login.html",
  "CallbackPage": "callback.html",

I would think this would be pretty transparent to Glewlwyd, since Nginx is rewriting the URLs as they come through. With this I can log in, log out, and get pages to load but callback redirects don't work. I get a 400 error about scope with the following:

image

Is there something else I need to do, or a better way, to accomplish Nginx as a reverse proxy aimed at Glewlwyd in a subfolder?

babelouest commented 4 years ago

In the endpoint GET /auth/scheme, the API returns an error 400 if the scope parameter is empty. My intuition is that your nginx proxy configuration doesn't pass the query parameters to Glewlwyd.

RNCTX commented 4 years ago

That was my suspicion as well. I found the other report awhile back about having to manually add the authorization header. Will work on the Nginx docs a bit and report back for others when I get it working, thanks!

babelouest commented 4 years ago

Will work on the Nginx docs a bit and report back for others when I get it working, thanks!

Thanks!

If you're ok, open a pull request to update the new section Reverse proxy configuration in the Install documentation with a new paragraph for Nginx proxy configuration.

RNCTX commented 4 years ago

Will do!

The answer to this is that there is no answer with location regex trickery, because Nginx will only pass URL queries and params if you modify the URL via rewrite, so here's a working config for Nginx in a subfolder:

 # Glewlwyd
        location ^~ /authsrv/ {
            rewrite ^\/authsrv(.*) /$1 break;
            proxy_set_header Authorization $http_authorization;
            proxy_set_header Host $host;
            proxy_pass http://127.0.0.1:4593;
        }

This will listen on the subdirectory https://site.url/authsrv but pass all requests to the backend at the root URL the backend expects. Only the webapp config needs to be changed to reflect the /authsrv directory for redirect purposes.

I'll submit a docs PR later with examples for both a root URL with Nginx and a subdirectory with Nginx.

babelouest commented 4 years ago

Nice!

Why must the header Authorization be specifically passed in the proxy config? I assume all the other headers are forwarded. Is there an exception for the Authorization header?

I also assume this config goes for https reverse proxy as well?

babelouest commented 4 years ago

Also, I write it down here to not forget about it, but I'd like to add the client ssl certificate proxy config in the documentation. For what I've seen, I have to add the following settings:

ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client on | optional | optional_no_ca
proxy_set_header        SSL_CLIENT_CERT         $client_cert;
RNCTX commented 4 years ago

Yes, I tried to disable the certificate settings in the glewdwyd.conf but that got me an error, if I remember correctly, so it seems that one cannot comment them out even if SSL is disabled?

Why must the header Authorization be specifically passed in the proxy config? I assume all the other headers are forwarded. Is there an exception for the Authorization header?

Because Nginx ignores any headers not present in the initial request of a session. I presume that in the glewlwyd web app an unauthorized user has no Authentication header until they log in, so Nginx will not pass it in subsequent requests unless it is explicitly declared for the first request.

I also assume this config goes for https reverse proxy as well?

It should, but anyone wanting to pass SSL through Nginx as a proxy should not be bothering with certificates at the proxy, when they can use ssl_preread (optional module under the "stream" set of Nginx addons) that allows Nginx to sniff out the address, but send the encrypted packets on through unmodified. By doing that, an SSL pass-through proxy with Nginx is very simple, just a qualified domain to listen on and a host map that the domain proxies to with whatever load balancing rules, if any.

Here's a whole Nginx config for multiple domains with load balancing (I have multiple OS virtual machines to test Ansible deployment scripts on, so I load balance them on a single domain, domain1, based on which one is booted up at any given time) running on my home consumer-grade router with ~256mb of RAM and an ARM cpu. No includes, no certificates, just ssl_preread.

user  nobody nobody;
worker_processes  2;
error_log syslog:server=192.168.1.80,facility=local7,tag=nginx_proxy,severity=warn;
lock_file /tmp/var/lock/nginx.lock;
pid       /tmp/var/run/nginx.pid;

events {
    worker_connections  512;
    multi_accept on;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  0;
    gzip  off;
    access_log syslog:server=192.168.1.80,facility=local7,tag=nginx_proxy;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    map_hash_bucket_size 64;

stream {
    map_hash_bucket_size 64;

    map $ssl_preread_server_name $name {
    domain1.tld.net domain1;
    domain2.tld.net domain2;
    domain3.tld.net domain3;
    default domain1;
    }
upstream domain1 {
    server 192.168.1.100:443 max_fails=0 fail_timeout=3s;
    server 192.168.1.101:443 max_fails=0 fail_timeout=3s;
    server 192.168.1.103:443 max_fails=0 fail_timeout=3s;
    server 192.168.1.104:443 max_fails=0 fail_timeout=3s;
    server 192.168.1.105:443 max_fails=0 fail_timeout=3s;
    }
upstream domain2 {
    server 192.168.1.80:443 max_fails=0 fail_timeout=3s;
    }
upstream domain3 {
    server 192.168.1.80:443 max_fails=0 fail_timeout=3s;
    }
server {
    listen 443;
    proxy_pass $name;
    ssl_preread on;
    access_log off;
    }
}
babelouest commented 4 years ago

Because Nginx ignores any headers not present in the initial request of a session

Not really stateless but ok

I presume that in the glewlwyd web app an unauthorized user has no Authentication header until they log in

Well, technically, Glewlwyd's webapp uses session cookies to authenticate users. The Authorization header is used in the oidc and oauth2 plugins.

It should, but anyone wanting to pass SSL through Nginx as a proxy should not be bothering with certificates at the proxy,

I'm not sure we're talking about the same thing, I was talking about having a Nginx as a reverse proxy, listening on https:// and forwarding to a glewlwyd on http://.

Thanks for the pull request! I think this bug can be closed now, don't you?

RNCTX commented 4 years ago

Yes, this is all working fine for me. I'll post back in this thread about what I find with the Authorization header. I found your project after failing to get Keycloak to work for a couple of days with an API backend that I am trying to evaluate, which simply would not authenticate properly no matter what I tried (using openid).

Yours is much lighter which is also a plus for a small server without much RAM, but after setting up both I wonder if Nginx not passing Authorization with proxy requests was the issue all along. I'm going by the report in #32 about the need to add it.