outposts: set cookies for a domain to authenticate an entire domain (#971)
* outposts: initial cookie domain implementation Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: add cookie domain setting Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * providers/proxy: replace forward_auth_mode with general mode Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: rebuild proxy provider form Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * providers/proxy: re-add forward_auth_mode for backwards compat Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: fix data.mode not being set Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * root: always set log level to debug when testing Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * providers/proxy: use new mode attribute Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * providers/proxy: only ingress /akprox on forward_domain Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * providers/proxy: fix lint error Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: fix error on ProxyProviderForm when not using proxy mode Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: fix default for outpost form's type missing Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: add additional desc for proxy modes Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * outposts: fix service account permissions not always being updated Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * outpost/proxy: fix redirecting to incorrect host for domain mode Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: improve error handling for network errors Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * outpost: fix image naming not matching main imaeg Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * outposts/proxy: fix redirects for domain mode and traefik Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: fix colour for paragraphs Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/flows: fix consent stage not showing permissions correctly Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * website/docs: add domain-level docs Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * website/docs: fix broken links Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * outposts/proxy: remove dead code Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/flows: fix missing id for #header-text Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
@ -65,7 +65,7 @@ type OAuthProxy struct {
|
||||
AuthOnlyPath string
|
||||
UserInfoPath string
|
||||
|
||||
forwardAuthMode bool
|
||||
mode api.ProxyMode
|
||||
redirectURL *url.URL // the url to receive requests at
|
||||
whitelistDomains []string
|
||||
provider providers.Provider
|
||||
@ -77,6 +77,7 @@ type OAuthProxy struct {
|
||||
PassUserHeaders bool
|
||||
BasicAuthUserAttribute string
|
||||
BasicAuthPasswordAttribute string
|
||||
ExternalHost string
|
||||
PassAccessToken bool
|
||||
SetAuthorization bool
|
||||
PassAuthorization bool
|
||||
@ -136,7 +137,7 @@ func NewOAuthProxy(opts *options.Options, provider api.ProxyOutpostConfig, c *ht
|
||||
CookieRefresh: opts.Cookie.Refresh,
|
||||
CookieSameSite: opts.Cookie.SameSite,
|
||||
|
||||
forwardAuthMode: *provider.ForwardAuthMode,
|
||||
mode: *provider.Mode,
|
||||
RobotsPath: "/robots.txt",
|
||||
SignInPath: fmt.Sprintf("%s/sign_in", opts.ProxyPrefix),
|
||||
SignOutPath: fmt.Sprintf("%s/sign_out", opts.ProxyPrefix),
|
||||
@ -216,43 +217,6 @@ func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, m
|
||||
}
|
||||
}
|
||||
|
||||
// splitHostPort separates host and port. If the port is not valid, it returns
|
||||
// the entire input as host, and it doesn't check the validity of the host.
|
||||
// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
|
||||
// *** taken from net/url, modified validOptionalPort() to accept ":*"
|
||||
func splitHostPort(hostport string) (host, port string) {
|
||||
host = hostport
|
||||
|
||||
colon := strings.LastIndexByte(host, ':')
|
||||
if colon != -1 && validOptionalPort(host[colon:]) {
|
||||
host, port = host[:colon], host[colon+1:]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
|
||||
host = host[1 : len(host)-1]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// validOptionalPort reports whether port is either an empty string
|
||||
// or matches /^:\d*$/
|
||||
// *** taken from net/url, modified to accept ":*"
|
||||
func validOptionalPort(port string) bool {
|
||||
if port == "" || port == ":*" {
|
||||
return true
|
||||
}
|
||||
if port[0] != ':' {
|
||||
return false
|
||||
}
|
||||
for _, b := range port[1:] {
|
||||
if b < '0' || b > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en
|
||||
var noCacheHeaders = map[string]string{
|
||||
"Expires": time.Unix(0, 0).Format(time.RFC1123),
|
||||
@ -340,18 +304,41 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) {
|
||||
func (p *OAuthProxy) AuthenticateOnly(rw http.ResponseWriter, req *http.Request) {
|
||||
session, err := p.getAuthenticatedSession(rw, req)
|
||||
if err != nil {
|
||||
if p.forwardAuthMode {
|
||||
if p.mode == api.PROXYMODE_FORWARD_SINGLE || p.mode == api.PROXYMODE_FORWARD_DOMAIN {
|
||||
if _, ok := req.URL.Query()["nginx"]; ok {
|
||||
rw.WriteHeader(401)
|
||||
return
|
||||
}
|
||||
if _, ok := req.URL.Query()["traefik"]; ok {
|
||||
host := getHost(req)
|
||||
host := ""
|
||||
// Optional suffix, which is appended to the URL
|
||||
suffix := ""
|
||||
if p.mode == api.PROXYMODE_FORWARD_SINGLE {
|
||||
host = getHost(req)
|
||||
} else if p.mode == api.PROXYMODE_FORWARD_DOMAIN {
|
||||
host = p.ExternalHost
|
||||
// set the ?rd flag to the current URL we have, since we redirect
|
||||
// to a (possibly) different domain, but we want to be redirected back
|
||||
// to the application
|
||||
v := url.Values{
|
||||
// see https://doc.traefik.io/traefik/middlewares/forwardauth/
|
||||
// X-Forwarded-Uri is only the path, so we need to build the entire URL
|
||||
"rd": []string{fmt.Sprintf(
|
||||
"%s://%s%s",
|
||||
req.Header.Get("X-Forwarded-Proto"),
|
||||
req.Header.Get("X-Forwarded-Host"),
|
||||
req.Header.Get("X-Forwarded-Uri"),
|
||||
)},
|
||||
}
|
||||
suffix = fmt.Sprintf("?%s", v.Encode())
|
||||
}
|
||||
proto := req.Header.Get("X-Forwarded-Proto")
|
||||
if proto != "" {
|
||||
proto = proto + ":"
|
||||
}
|
||||
http.Redirect(rw, req, fmt.Sprintf("%s//%s%s", proto, host, p.OAuthStartPath), http.StatusTemporaryRedirect)
|
||||
rdFinal := fmt.Sprintf("%s//%s%s%s", proto, host, p.OAuthStartPath, suffix)
|
||||
p.logger.WithField("url", rdFinal).Debug("Redirecting to login")
|
||||
http.Redirect(rw, req, rdFinal, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -360,7 +347,7 @@ func (p *OAuthProxy) AuthenticateOnly(rw http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
// we are authenticated
|
||||
p.addHeadersForProxying(rw, req, session)
|
||||
if p.forwardAuthMode {
|
||||
if p.mode == api.PROXYMODE_FORWARD_SINGLE || p.mode == api.PROXYMODE_FORWARD_DOMAIN {
|
||||
for headerKey, headers := range req.Header {
|
||||
for _, value := range headers {
|
||||
rw.Header().Set(headerKey, value)
|
||||
|
Reference in New Issue
Block a user