-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
Add forward authentication option #1972
Conversation
Wow, great job @drampelt ! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice improvement!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @drampelt, great job!
I made few comments though.
auth/forward.go
Outdated
return | ||
} | ||
|
||
defer forwardResponse.Body.Close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would move this line after the block:
if readError != nil {
...
}
defer forwardResponse.Body.Close()
Indeed, if readError
is not nil, maybe the body will be empty, then the defered Close()
would lead to a panic.
types/types.go
Outdated
@@ -314,6 +315,11 @@ type Digest struct { | |||
UsersFile string | |||
} | |||
|
|||
// Forward authentication | |||
type Forward struct { | |||
Address string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be great to add the possibility to connect in TLS (with an self-signed cert).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm agree with @emilevauge for the TLS connection.
Indeed, for example, I tried to test the PR by connecting Traefik to a docker_auth server but this server allows only HTTPS connections...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree that would be useful. Unfortunately I'm not too familiar with Go yet and not really sure how to go about doing that - would anyone else be interested in implementing that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem @drampelt.
We can do the modifications for your 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick review.
auth/forward.go
Outdated
func Forward(forward *types.Forward, w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { | ||
client := http.Client{} | ||
|
||
forwardReq, err := http.NewRequest("GET", forward.Address, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"GET" -> http.methodGet
auth/forward.go
Outdated
return | ||
} | ||
|
||
if forwardResponse.StatusCode < 200 || forwardResponse.StatusCode >= 300 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you replace:
200
byhttp.StatusOK
300
byhttp.StatusMultipleChoices
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe the limit can be 400
instead of 300
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose 300 to allow the auth server to redirect to a login page if necessary. For example if doing Google sign in, the auth server would need to redirect the user to Google by returning a 302.
middlewares/authenticator.go
Outdated
"github.com/abbot/go-http-auth" | ||
goauth "github.com/abbot/go-http-auth" | ||
|
||
"github.com/containous/traefik/auth" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you sort imports?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, could you clarify what order they should be in? I'm not too familiar with Go yet and gofmt seems to think that is fine.
@drampelt The code freeze for 1.4 will happen in 2 days (August 25th). Do you think you will be able to fix your PR in the meantime ? |
Thanks for the reviews, I have a fairly busy week but I'll see if I can get it fixed up by tomorrow. |
Fixed most of the issues I knew how to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Marathon part LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many thanks for this really useful PR.
LGTM 👏 👏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
d25a773
to
26f7121
Compare
Hi I used github as an example to test defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth.forward]
address = "http://github.com/login/oauth/authorize"
[web]
address = ":8081"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://localhost:8000"
[frontends]
[frontends.frontend1]
backend = "backend1"
passHostHeader = true
[frontends.frontend1.routes.example]
rule = "Host:localhost" If I try to hit localhost i simply hit my local server on port 8000 with no auth request. |
@RC1140 Thanks for your interest in Traefik 😃 Please discuss this in :
|
Description
This implements forward authentication, much like in
ngx_http_auth_request_module
.Based on the discussion in #1030 and Proposal Doc, it's clear we needed to start with something simple and then build on it later. This implementation is a simplified version of @vladshub's implementation in #1030, removing the request and response body header/query parameter manipulation.
When forward auth is enabled, the request is first forwarded to the specified auth server. If the auth server responds with a 2XX status, the original request is performed. Otherwise, the response from the auth server is returned.
Next steps
If everyone agrees this is a good starting point, I think the next step would be either copying or renaming response headers from the auth server as request headers sent to the backend.
From what I can tell that seems to be the main use-case, the auth server provides authenticated user information in response headers and then the backend application uses that information to automatically authenticate the user. See oauth2_proxy with nginx as an example of this. I believe this would bring it to feature parity with
ngx_http_auth_request_module
.See this commit for a potential implementation of header mapping.
Of course I'm open to discussion about how to proceed and interested in hearing other ideas.