diff options
author | ngala <ngala@gitlab.com> | 2023-11-10 09:50:05 +0300 |
---|---|---|
committer | ngala <ngala@gitlab.com> | 2023-11-10 09:50:05 +0300 |
commit | 62c52f5cff34e307a0519a915afb55f8315deff9 (patch) | |
tree | bb6eb18b224b60bf1ea09f237a3e499774a3e029 | |
parent | ceb6d345d860dc8c6cce1d92278858f154f14440 (diff) |
Add test for X-Gitlab-Namespace-In-Path
-rw-r--r-- | internal/auth/auth.go | 6 | ||||
-rw-r--r-- | internal/auth/session.go | 9 | ||||
-rw-r--r-- | internal/request/request.go | 13 | ||||
-rw-r--r-- | internal/request/request_test.go | 37 |
4 files changed, 55 insertions, 10 deletions
diff --git a/internal/auth/auth.go b/internal/auth/auth.go index ad35c3e9..bbb8daa6 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -142,7 +142,7 @@ func (a *Auth) checkAuthenticationResponse(session *hostSession, w http.Response return } - decryptedCode, err := a.DecryptCode(r.URL.Query().Get("code"), getRequestDomain(r, getNamespaceInPath(session))) + decryptedCode, err := a.DecryptCode(r.URL.Query().Get("code"), getRequestDomain(r, getNamespaceInPathFromSession(session))) if err != nil { logRequest(r).WithError(err).Error("failed to decrypt secure code") errortracking.CaptureErrWithReqAndStackTrace(err, r) @@ -333,7 +333,7 @@ func getRequestDomain(r *http.Request, namespace string) string { return "http://" + requestDomain } -func getNamespaceInPath(session *hostSession) string { +func getNamespaceInPathFromSession(session *hostSession) string { namespaceInPath := "" if len(session.Options.Path) > 1 && session.Options.Path[0] == '/' { namespaceInPath = session.Options.Path[1:] @@ -459,7 +459,7 @@ func (a *Auth) checkTokenExists(session *hostSession, w http.ResponseWriter, r * // Because the pages domain might be in public suffix list, we have to // redirect to pages domain to trigger authorization flow - http.Redirect(w, r, a.getProxyAddress(r, session.Values["state"].(string), getNamespaceInPath(session)), http.StatusFound) + http.Redirect(w, r, a.getProxyAddress(r, session.Values["state"].(string), getNamespaceInPathFromSession(session)), http.StatusFound) return true } diff --git a/internal/auth/session.go b/internal/auth/session.go index 9a14e7f0..bbe83ba5 100644 --- a/internal/auth/session.go +++ b/internal/auth/session.go @@ -2,12 +2,10 @@ package auth import ( "github.com/gorilla/sessions" - "net/http" - "strings" - "gitlab.com/gitlab-org/gitlab-pages/internal/errortracking" "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" "gitlab.com/gitlab-org/gitlab-pages/internal/request" + "net/http" ) type hostSession struct { @@ -28,10 +26,7 @@ func (a *Auth) getSessionFromStore(r *http.Request) (*hostSession, error) { session, err := a.store.Get(r, "gitlab-pages") if session != nil { - namespaceInPath := r.Header.Get("X-Gitlab-Namespace-In-Path") - if namespaceInPath != "" && !strings.HasPrefix(r.Host, namespaceInPath+"."+a.pagesDomain) { - namespaceInPath = "" - } + namespaceInPath := request.GetNamespaceInPathFromRequest(r, a.pagesDomain) logRequest(r).WithField("X-Gitlab-Namespace-In-Path", namespaceInPath).Debug("> Inside getSessionFromStore") // Cookie just for this domain diff --git a/internal/request/request.go b/internal/request/request.go index f98b0819..4a7e1e52 100644 --- a/internal/request/request.go +++ b/internal/request/request.go @@ -3,6 +3,7 @@ package request import ( "net" "net/http" + "strings" ) const ( @@ -38,3 +39,15 @@ func GetRemoteAddrWithoutPort(r *http.Request) string { return remoteAddr } + +// GetNamespaceInPathFromRequest GetNamespaceInPath fetches X-Gitlab-Namespace-In-Path from r.Header and validates against pagesDomain before returning +func GetNamespaceInPathFromRequest(r *http.Request, pagesDomain string) string { + namespaceInPath := "" + if pagesDomain != "" { + namespaceInPath = r.Header.Get("X-Gitlab-Namespace-In-Path") + if namespaceInPath != "" && !strings.HasPrefix(r.Host, namespaceInPath+"."+pagesDomain) { + namespaceInPath = "" + } + } + return namespaceInPath +} diff --git a/internal/request/request_test.go b/internal/request/request_test.go index 9e71db37..8ee16f8c 100644 --- a/internal/request/request_test.go +++ b/internal/request/request_test.go @@ -87,3 +87,40 @@ func TestGetRemoteAddrWithoutPort(t *testing.T) { }) } } + +func TestGetNamespaceInPathFromRequest(t *testing.T) { + tests := map[string]struct { + pagesDomain string + u string + namespace string + expected string + }{ + "when valid X-Gitlab-Namespace-In-Path is provided in request header": { + pagesDomain: "example.com", + u: "https://namespace.example.com/myProject", + namespace: "namespace", + expected: "namespace", + }, + "when valid X-Gitlab-Namespace-In-Path with '.' in between in request header": { + pagesDomain: "example.com", + u: "https://namespace.test.example.com/myProject", + namespace: "namespace.test", + expected: "namespace.test", + }, + "when forged X-Gitlab-Namespace-In-Path is provided in request header": { + pagesDomain: "example.com", + u: "https://namespace.example.com/myProject", + namespace: "namespace-forged", + expected: "", + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, test.u, nil) + req.Header.Set("X-Gitlab-Namespace-In-Path", test.namespace) + + namespace := GetNamespaceInPathFromRequest(req, test.pagesDomain) + require.Equal(t, test.expected, namespace) + }) + } +} |