diff --git a/go.mod b/go.mod index 550371c9e3a4..5178ff0bb234 100644 --- a/go.mod +++ b/go.mod @@ -135,4 +135,5 @@ replace ( github.com/gogo/protobuf => github.com/gravitational/protobuf v1.3.2-0.20201123192827-2b9fcfaffcbf github.com/gravitational/teleport/api => ./api github.com/siddontang/go-mysql v1.1.0 => github.com/gravitational/go-mysql v1.1.1-0.20210212011549-886316308a77 + github.com/julienschmidt/httprouter => github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5 ) diff --git a/go.sum b/go.sum index 012ab849cf17..a9ca7dec4a1d 100644 --- a/go.sum +++ b/go.sum @@ -359,6 +359,8 @@ github.com/gravitational/go-mysql v1.1.1-0.20210212011549-886316308a77 h1:ivambM github.com/gravitational/go-mysql v1.1.1-0.20210212011549-886316308a77/go.mod h1:re0JQZ1Cy5dVlIDGq0YksfDIla/GRZlxqOoC0XPSSGE= github.com/gravitational/go-oidc v0.0.6 h1:DCllahGYxDAvxWsq8UILgO+/i1EheQRxcNzS+D+wP5I= github.com/gravitational/go-oidc v0.0.6/go.mod h1:SevmOUNdOB0aD9BAIgjptZ6oHkKxMZZgA70nwPfgU/w= +github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5 h1:qg8FcGwRACSHortU1UxCSo9nF0t34rPWjk9Nef3j2Ic= +github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/gravitational/kingpin v2.1.11-0.20190130013101-742f2714c145+incompatible h1:CfyZl3nyo9K5lLqOmqvl9/IElY1UCnOWKZiQxJ8HKdA= github.com/gravitational/kingpin v2.1.11-0.20190130013101-742f2714c145+incompatible/go.mod h1:LWxG30M3FcrjhOn3T4zz7JmBoQJ45MWZmOXgy9Ganoc= github.com/gravitational/license v0.0.0-20210218173955-6d8fb49b117a h1:PN5vAN1ZA0zqdpM6wNdx6+bkdlQ5fImd75oaIHSbOhY= @@ -472,9 +474,6 @@ github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfE github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 777237678faf..58ad99e625dd 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -89,6 +89,7 @@ func NewAPIServer(config *APIConfig) (http.Handler, error) { Clock: clockwork.NewRealClock(), } srv.Router = *httprouter.New() + srv.Router.UseRawPath = true // Kubernetes extensions srv.POST("/:version/kube/csr", srv.withAuth(srv.processKubeCSR)) diff --git a/lib/httplib/httplib_test.go b/lib/httplib/httplib_test.go index 9b7ff1e7c70e..ce69f6d91a71 100644 --- a/lib/httplib/httplib_test.go +++ b/lib/httplib/httplib_test.go @@ -62,6 +62,7 @@ type testHandler struct { func newTestHandler() *testHandler { h := &testHandler{} h.Router = *httprouter.New() + h.Router.UseRawPath = true h.POST("/v1/sessions/:id/stream", MakeHandler(h.postSessionChunkOriginal)) h.POST("/v1/namespaces/:namespace/sessions/:id/stream", MakeHandler(h.postSessionChunkNamespace)) return h diff --git a/lib/kube/proxy/forwarder.go b/lib/kube/proxy/forwarder.go index 09dd5520cf0f..8dd018bee8c0 100644 --- a/lib/kube/proxy/forwarder.go +++ b/lib/kube/proxy/forwarder.go @@ -237,6 +237,8 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { close: close, } + fwd.router.UseRawPath = true + fwd.router.POST("/api/:ver/namespaces/:podNamespace/pods/:podName/exec", fwd.withAuth(fwd.exec)) fwd.router.GET("/api/:ver/namespaces/:podNamespace/pods/:podName/exec", fwd.withAuth(fwd.exec)) diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index e883a70a6cdf..3f16a8f3fc6a 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -225,6 +225,9 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { clusterFeatures: cfg.ClusterFeatures, } + // for properly handling url-encoded parameter values. + h.UseRawPath = true + for _, o := range opts { if err := o(h); err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/app/handler.go b/lib/web/app/handler.go index 2fd787191311..4497b3cedb76 100644 --- a/lib/web/app/handler.go +++ b/lib/web/app/handler.go @@ -121,6 +121,7 @@ func NewHandler(ctx context.Context, c *HandlerConfig) (*Handler, error) { // Create the application routes. h.router = httprouter.New() + h.router.UseRawPath = true h.router.GET("/x-teleport-auth", makeRouterHandler(h.handleFragment)) h.router.POST("/x-teleport-auth", makeRouterHandler(h.handleFragment)) h.router.GET("/teleport-logout", h.withRouterAuth(h.handleLogout)) diff --git a/vendor/github.com/julienschmidt/httprouter/router.go b/vendor/github.com/julienschmidt/httprouter/router.go index 599529d198f6..4dbc5b2b7e92 100644 --- a/vendor/github.com/julienschmidt/httprouter/router.go +++ b/vendor/github.com/julienschmidt/httprouter/router.go @@ -182,6 +182,13 @@ type Router struct { // The handler can be used to keep your server from crashing because of // unrecovered panics. PanicHandler func(http.ResponseWriter, *http.Request, interface{}) + + // Go 1.5 introduced the RawPath field in net/url to hold the encoded form of Path. + // The Parse function sets both Path and RawPath in the URL it returns, + // and URL's String method uses RawPath if it is a valid encoding of Path, + // by calling the EncodedPath method. + // This tells the router to use the request.URL.RawPath when parsing the path. + UseRawPath bool } // Make sure the Router conforms with the http.Handler interface @@ -195,6 +202,7 @@ func New() *Router { RedirectFixedPath: true, HandleMethodNotAllowed: true, HandleOPTIONS: true, + UseRawPath: false, } } @@ -382,6 +390,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { path := req.URL.Path + if r.UseRawPath && req.URL.RawPath != "" { + path = req.URL.RawPath + } + if root := r.trees[req.Method]; root != nil { if handle, ps, tsr := root.getValue(path); handle != nil { handle(w, req, ps) diff --git a/vendor/github.com/julienschmidt/httprouter/tree.go b/vendor/github.com/julienschmidt/httprouter/tree.go index c9fdf5b41da0..cef6a8a3cc9d 100644 --- a/vendor/github.com/julienschmidt/httprouter/tree.go +++ b/vendor/github.com/julienschmidt/httprouter/tree.go @@ -5,6 +5,7 @@ package httprouter import ( + "net/url" "strings" "unicode" "unicode/utf8" @@ -380,7 +381,13 @@ walk: // outer loop for walking the tree i := len(p) p = p[:i+1] // expand slice within preallocated capacity p[i].Key = n.path[1:] - p[i].Value = path[:end] + + value, err := url.PathUnescape(path[:end]) + if err != nil { + p[i].Value = path[:end] + } else { + p[i].Value = value + } // we need to go deeper! if end < len(path) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 37eec9475f56..c49401ed2595 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -425,8 +425,8 @@ github.com/json-iterator/go github.com/jstemmer/go-junit-report github.com/jstemmer/go-junit-report/formatter github.com/jstemmer/go-junit-report/parser -# github.com/julienschmidt/httprouter v1.3.0 -## explicit +# github.com/julienschmidt/httprouter v1.3.0 => github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5 +## explicit; go 1.7 github.com/julienschmidt/httprouter # github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 ## explicit @@ -1178,3 +1178,4 @@ sigs.k8s.io/yaml # github.com/coreos/go-oidc => github.com/gravitational/go-oidc v0.0.6 # github.com/gogo/protobuf => github.com/gravitational/protobuf v1.3.2-0.20201123192827-2b9fcfaffcbf # github.com/gravitational/teleport/api => ./api +# github.com/julienschmidt/httprouter => github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5