diff --git a/middleware/basic_auth.go b/middleware/basic_auth.go index a546c9e9..90883730 100644 --- a/middleware/basic_auth.go +++ b/middleware/basic_auth.go @@ -2,8 +2,8 @@ package middleware import ( "crypto/subtle" - "fmt" "net/http" + "strconv" ) // BasicAuth implements a simple middleware handler for adding basic http auth to a route. @@ -28,6 +28,6 @@ func BasicAuth(realm string, creds map[string]string) func(next http.Handler) ht } func basicAuthFailed(w http.ResponseWriter, realm string) { - w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm)) + w.Header().Add("WWW-Authenticate", "Basic realm="+strconv.Quote(realm)) w.WriteHeader(http.StatusUnauthorized) } diff --git a/middleware/basic_auth_test.go b/middleware/basic_auth_test.go new file mode 100644 index 00000000..da5d802b --- /dev/null +++ b/middleware/basic_auth_test.go @@ -0,0 +1,27 @@ +package middleware + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestBasicAuthEscapesRealm(t *testing.T) { + realm := `admin"ops\zone` + h := BasicAuth(realm, map[string]string{"user": "pass"})(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) {}, + )) + + rr := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, "/", nil) + h.ServeHTTP(rr, req) + + if rr.Code != http.StatusUnauthorized { + t.Fatalf("status code = %d, want %d", rr.Code, http.StatusUnauthorized) + } + + const want = `Basic realm="admin\"ops\\zone"` + if got := rr.Header().Get("WWW-Authenticate"); got != want { + t.Fatalf("WWW-Authenticate = %q, want %q", got, want) + } +}