diff --git a/CHANGELOG.md b/CHANGELOG.md index 90ee419b85dc31386a04b3a5df74268827ac6e05..743ef453a23f3914bcfc4c97133afa42d458e5ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ #### **2.0.4** +FIXES: + * Fixes a bug in authentication, which permitted double slashed url entry [#PR200](https://github.com/gambol99/keycloak-proxy/pull/200) + FEATURES: * Grabbing the revocation-url from the idp config if user override is not specified [#PR193](https://github.com/gambol99/keycloak-proxy/pull/193) diff --git a/doc.go b/doc.go index 020b8357f7b8e2d64230582038676ae0fdfab322..47cd03dace2d6c8c491320687aa5909d39594244 100644 --- a/doc.go +++ b/doc.go @@ -24,7 +24,7 @@ import ( ) var ( - release = "v2.0.3" + release = "v2.0.4" gitsha = "no gitsha provided" version = release + " (git+sha: " + gitsha + ")" ) diff --git a/middleware.go b/middleware.go index 13e4cc22ecdf52fba61189d9f418d419a8bac38a..2a0fa21db845459a4fa445ab208ed788a764b0bb 100644 --- a/middleware.go +++ b/middleware.go @@ -16,6 +16,7 @@ limitations under the License. package main import ( + "bytes" "fmt" "regexp" "strings" @@ -33,6 +34,22 @@ const ( cxEnforce = "Enforcing" ) +// filterMiddleware is custom filtering for incoming requests +func (r *oauthProxy) filterMiddleware() gin.HandlerFunc { + return func(cx *gin.Context) { + var p rune + var b bytes.Buffer + for _, c := range cx.Request.URL.Path { + if c == '/' && p == '/' { + continue + } + p = c + b.WriteRune(c) + } + cx.Request.URL.Path = b.String() + } +} + // loggingMiddleware is a custom http logger func (r *oauthProxy) loggingMiddleware() gin.HandlerFunc { return func(cx *gin.Context) { diff --git a/middleware_test.go b/middleware_test.go index c476107adfded8222dde4cafcb8b350749ca5ee1..2a8e93c762f28c4df68fbf4d953940663c80b44a 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -93,6 +93,54 @@ func TestRolePermissionsMiddleware(t *testing.T) { Redirects: true, Expects: http.StatusOK, }, + { // check for escaping + URI: "//admin%2Ftest", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for escaping + URI: "/admin%2Ftest", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for prefix slashs + URI: "//admin/test", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for prefix slashs + URI: "/admin//test", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for prefix slashs + URI: "/admin//test", + Redirects: false, + HasToken: true, + Expects: http.StatusForbidden, + }, + { // check for dodgy url + URI: "//admin/../admin/test", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for dodgy url + URI: "/help/../admin/test", + Redirects: true, + Expects: http.StatusTemporaryRedirect, + }, + { // check for it works + URI: "//admin/test", + HasToken: true, + Roles: []string{fakeAdminRole}, + Expects: http.StatusOK, + }, + { // check for it works + URI: "//admin//test", + HasToken: true, + Roles: []string{fakeAdminRole}, + Expects: http.StatusOK, + }, { // check with a token URI: "/", Redirects: false, diff --git a/server.go b/server.go index 87f10280ddc44bcd3fd7cf4529f4690ca75a1327..9dda7bfc0d6075b3507ce827cc7423760f0b7bb8 100644 --- a/server.go +++ b/server.go @@ -154,6 +154,9 @@ func (r *oauthProxy) createReverseProxy() error { // step: create the gin router engine := gin.New() engine.Use(gin.Recovery()) + // step: custom filtering + engine.Use(r.filterMiddleware()) + // step: is profiling enabled? if r.config.EnableProfiling { log.Warn("Enabling the debug profiling on /debug/pprof")