diff --git a/proxy/pkg/middleware/authentication.go b/proxy/pkg/middleware/authentication.go index 79a3964d0..dccef744f 100644 --- a/proxy/pkg/middleware/authentication.go +++ b/proxy/pkg/middleware/authentication.go @@ -75,3 +75,25 @@ func writeSupportedAuthenticateHeader(w http.ResponseWriter, r *http.Request) { w.Header().Add("WWW-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(SupportedAuthStrategies[i]), r.Host)) } } + +func removeSuperfluousAuthenticate(w http.ResponseWriter) { + w.Header().Del("Www-Authenticate") +} + +// userAgentAuthenticateLockIn sets Www-Authenticate according to configured user agents. This is useful for the case of +// legacy clients that do not support protocols like OIDC or OAuth and want to lock a given user agent to a challenge, +// such as basic. More info in https://github.com/cs3org/reva/pull/1350 +func userAgentAuthenticateLockIn(w http.ResponseWriter, req *http.Request, creds map[string]string, fallback string) { + for i := 0; i < len(ProxyWwwAuthenticate); i++ { + if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) { + for k, v := range creds { + if strings.Contains(k, req.UserAgent()) { + removeSuperfluousAuthenticate(w) + w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host)) + return + } + } + w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(fallback), req.Host)) + } + } +} diff --git a/proxy/pkg/middleware/basic_auth.go b/proxy/pkg/middleware/basic_auth.go index c0bea0fb7..c16eb8def 100644 --- a/proxy/pkg/middleware/basic_auth.go +++ b/proxy/pkg/middleware/basic_auth.go @@ -32,29 +32,14 @@ func BasicAuth(optionSetters ...Option) func(next http.Handler) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, req *http.Request) { if h.isPublicLink(req) || !h.isBasicAuth(req) { - // if we want to prevent duplicated Www-Authenticate headers coming from Reva consider using w.Header().Del("Www-Authenticate") - // but this will require the proxy being aware of endpoints which authentication fallback to Reva. if !h.isPublicLink(req) { - for i := 0; i < len(ProxyWwwAuthenticate); i++ { - if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) { - for k, v := range options.CredentialsByUserAgent { - if strings.Contains(k, req.UserAgent()) { - w.Header().Del("Www-Authenticate") - w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host)) - goto OUT - } - } - w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", "Basic", req.Host)) - } - } + userAgentAuthenticateLockIn(w, req, options.CredentialsByUserAgent, "basic") } - OUT: next.ServeHTTP(w, req) return } - w.Header().Del("Www-Authenticate") - + removeSuperfluousAuthenticate(w) account, ok := h.getAccount(req) // touch is a user agent locking guard, when touched changes to true it indicates the User-Agent on the @@ -63,10 +48,9 @@ func BasicAuth(optionSetters ...Option) func(next http.Handler) http.Handler { touch := false if !ok { - // if the request is bound to a user agent the locked write Www-Authenticate for such user for k, v := range options.CredentialsByUserAgent { if strings.Contains(k, req.UserAgent()) { - w.Header().Del("Www-Authenticate") + removeSuperfluousAuthenticate(w) w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host)) touch = true break diff --git a/proxy/pkg/middleware/oidc_auth.go b/proxy/pkg/middleware/oidc_auth.go index b91c3b395..098ff8d07 100644 --- a/proxy/pkg/middleware/oidc_auth.go +++ b/proxy/pkg/middleware/oidc_auth.go @@ -3,7 +3,6 @@ package middleware import ( "context" "encoding/json" - "fmt" "net/http" "strings" "time" @@ -41,19 +40,7 @@ func OIDCAuth(optionSetters ...Option) func(next http.Handler) http.Handler { // there is no bearer token on the request, if !h.shouldServe(req) { // oidc supported but token not present, add header and handover to the next middleware. - for i := 0; i < len(ProxyWwwAuthenticate); i++ { - if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) { - for k, v := range options.CredentialsByUserAgent { - if strings.Contains(k, req.UserAgent()) { - w.Header().Del("Www-Authenticate") - w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host)) - goto OUT - } - } - w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", "Bearer", req.Host)) - } - } - OUT: + userAgentAuthenticateLockIn(w, req, options.CredentialsByUserAgent, "bearer") next.ServeHTTP(w, req) return }