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

Using reauth with proxy #27

Open
dcode opened this issue May 22, 2019 · 13 comments
Open

Using reauth with proxy #27

dcode opened this issue May 22, 2019 · 13 comments

Comments

@dcode
Copy link

dcode commented May 22, 2019

I'm trying to serve an application via proxy (in this case Kibana, but similar usecase is Django, Flask, or Rails. I'm relatively new to Caddy, so I could have some basic misunderstanding of the config as well.

I have static files stored under /srv/app/static that I would like protected by a reauth upstream authorization. To the user, it would appear that all the pages are protected by the application's login screen. Since it's all hosted on the same host endpoint, auth cookies will be passed, etcd.

Here's my current config (I'm running this in docker):

0.0.0.0 {
    proxy / kibana:5601 {
        except /app/static
    }

    reauth {
        path /app/static
        upstream url=http://kibana:5601/app/kibana,cookies=true
        failure redirect target=/login?next={uri}
    }

    root /srv
    log stdout
    errors stdout
}

When I browse to localhost:2015, Kibana correctly picks up the request via the proxy block above. When I am not authenticated, I get redirected to the Kibana login page (/login?next=%2F). However, when I browse to localhost:2015/app/static, I get a status 500. I can see in the logs that Kibana is in fact receiving the auth request from Caddy.

proxy_1          | 22/May/2019:14:39:47 +0000 [ERROR 500 /app/static/] Get /login?next=%2Fapp%2Fkibana: follow redirects disabled
proxy_1          | 172.22.0.1 - - [22/May/2019:14:39:47 +0000] "GET /app/static/ HTTP/1.1" 500 26
kibana_1         | {"type":"response","@timestamp":"2019-05-22T14:39:47Z","tags":[],"pid":1,"method":"get","statusCode":302,"req":{"url":"/app/kibana","method":"get","headers":{"host":"kibana:5601","user-agent":"Go-http-client/1.1","accept-encoding":"gzip"},"remoteAddress":"172.22.0.2","userAgent":"172.22.0.2"},"res":{"statusCode":302,"responseTime":5,"contentLength":9},"message":"GET /app/kibana 302 5ms - 9.0B"}

However, if I am already authenticated to Kibana, it places a cookie called sid (by default).

I saw the error follow redirects disabled in the unauthenticated example, and so I thought maybe I need to apply redirects to the upstream backend. The problem here is that Kibana provides a redirect 302, and the login page /login sends a 200.

What am I doing wrong and/or how can I get more info?

Side note, my first attempt to do this was the following. I kept getting the 500 and was getting frustrated thinking I was doing something wrong. After doing the analysis above, I think the logic is effectively the same. The config below is nicer since I don't have to create an arbitrary dir structure in the root to support the URI subpath.

0.0.0.0 {
    proxy / kibana:5601 {
        except /app/static
    }
   log stdout
   errors stdout
}
0.0.0.0/app/static {
    reauth {
        path /app/static
        upstream url=http://kibana:5601/app/kibana,cookies=true
        failure redirect target=/login?next={uri}
    }

    root /srv
    log stdout
    errors stdout
}
@freman
Copy link
Owner

freman commented May 23, 2019

Have you tried adding ,follow=true to your upstream line? that should permit it to follow the redirect.

@dcode
Copy link
Author

dcode commented May 23, 2019

I did, but that authorizes all traffic because the redirect for auth takes you to a login form that returns a 200.

It seems to me that the failure line should generate a redirect response to the browser, not follow a redirect itself.

@freman
Copy link
Owner

freman commented May 23, 2019

right right, sorry, I've had an injection of coffee now.

upstream url=http://kibana:5601/app/kibana,cookies=true should be performing failure redirect target=/login?next={uri} when it fails.

So the problem probably is in the detection of kibana saying user needs auth.
Because kibana does a redirect on auth failure and the code is like "nope"

Seems like I need to patch to make it smarter, perhaps allow a match. eg
something like...
upstream url=http://kibana:5601/app/kibana,cookies=true,oncode=303,match=/login/

Would allow it to decide the user needs logging in when it see's a 303 redirect to a url containing a login.

I can do this patch for you tonight.

@dcode
Copy link
Author

dcode commented May 23, 2019

so then, I'd be able to do ,follow=true and the failure action for redirect would work? I'd be happy to try a patch whenever you get it ready! Thanks for the quick effort!

@freman
Copy link
Owner

freman commented May 23, 2019

76783e7 this should do it for you

So your config should look something like

        upstream url=http://kibana:5601/app/kibana,cookies=true,follow=true,match=login

I've submitted the build to caddy but if you're impatient you can build it by hand :D

edit: It seems that building it by hand might be the way to go

plugin deploy failed
go vet github.com/freman/[email protected]: timed out (buildworker-enforced)

that's outside of my control :(

@dcode
Copy link
Author

dcode commented May 24, 2019

Yeah, that's no problem I use https://github.com/abiosoft/caddy-docker to build a container of caddy anyway, and it pulls master of all selected plugins, so I'm building it now. I'll report back my outcome.

@dcode
Copy link
Author

dcode commented May 24, 2019

Okay, so the auth works now, thanks! I'm still having issue on the redirect now, but just with the placeholder. Ideally, after the login, I'd like to get redirected back to the original URI.

(I think) this is the relevant part of my Caddyfile:

0.0.0.0/app/static/ {
    header / {
	X-Requested-URI {uri}
        X-Requested-Path {path}
	X-Requested-Dir {dir}
	X-Requested-File {file}
    }

    reauth {
        path /
	upstream url=http://kibana:5601/app/kibana,cookies=true,follow=true,match=login
        failure redirect target=/login?next={uri}
    }

    root /srv
    log stdout
    errors stdout
}

The authentication check works as desired, and will send the browser a redirect. But the {uri} is being populated as /.

HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: /login?next=%2F
Server: Caddy
X-Requested-Dir: /
X-Requested-File: 
X-Requested-Path: /app/static/
X-Requested-Uri: /app/static/
Date: Fri, 24 May 2019 11:44:25 GMT
Content-Length: 38

I think this is happening because my site definition is using patch matching. I noticed that for the path value in the reauth block I have to specify /, or else it doesn't trigger. It seems the http.Request object being passed to the plugin has a context of the path, not the original request.

Here you're using the raw http.Request URL value to populate {uri}, but the Caddy placeholder logic references OriginalURLCtxKey, which I don't know where that comes from. And I've reached the limit of my Golang knowledge. The {dir} placeholder shown also is substituteded as /, which looking at the code, Caddy doesn't retrieve the original context here. So I think that all fits together.

Is it crazy hard to use the Caddy placedholder functions to get the original context or get the original context through "magic means" like the Caddy replace function does? This is technically a different problem and I can open a different issue, if you'd prefer.

Thanks again for being so quick to fix my redirect problem. That makes my use at least functional.

@freman
Copy link
Owner

freman commented May 24, 2019

No that's fine, and I suspect you've finally been able to help me figure out the issues the others were having.

I'll have a look later it actually shouldn't be that hard. I have access to your original url elsewhere in the request I can store that and reuse it if I can't find it elsewhere

@freman
Copy link
Owner

freman commented May 27, 2019

Hmm, so I wrote a test case to check the reason I thought it was broken, but that doesn't seem to be it.

I can cirtainly look at populating the url with 'OriginalURLCtxKey' but can you do me a quick check?

try adding

    except /login

to your reauth block so it doesn't try authenticating the /login call recursively

@dcode
Copy link
Author

dcode commented Jun 6, 2019

@freman sorry, I thought I got back to you. This didn't change anything because /login takes another route. My full Caddyfile is here: https://gist.github.com/dcode/5b013cfc32e7482e4b6a8061203aa99d

@freman
Copy link
Owner

freman commented Jun 11, 2019

Sorry, just been a little busy at work but I'll take another look and see if I can't replicate what's happening and get you a fix this week.

@dcode
Copy link
Author

dcode commented Jun 11, 2019

Hey, man. No problem. I maintain an open source project too, and sometimes it just takes a bit. No biggie. Thanks for your work though. Super excited about the possibilities.

@macross5
Copy link

macross5 commented Apr 8, 2020

I get a similar error:
[ERROR 500 /favicon.ico] Get http://heimdall/login: follow redirects disabled
My config:

failure redirect target=https://xxx:yyyy/login,code=302
upstream url=http://heimdall:80,cookies=true

When i add follow=true,match=login to the upstream url, then all requests are allowed.
When i remove the cookies=true with follow=true,match=login it ends in an endless loop.

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

No branches or pull requests

3 participants