diff options
author | Vladimir Shushlin <vshushlin@gitlab.com> | 2019-06-03 14:22:03 +0300 |
---|---|---|
committer | Nick Thomas <nick@gitlab.com> | 2019-06-03 14:22:03 +0300 |
commit | 9df35356572e09dc2c0907113bf64479204e46a9 (patch) | |
tree | 70297534cace3ad4c6015df32757690cc9244992 /internal/domain | |
parent | 80fa0bb4e200a6b3b9194766dd209de28d1cf08a (diff) |
Redirect unknown ACME challenges to the GitLab instance
Diffstat (limited to 'internal/domain')
-rw-r--r-- | internal/domain/domain.go | 34 | ||||
-rw-r--r-- | internal/domain/domain_test.go | 97 | ||||
-rw-r--r-- | internal/domain/map_test.go | 2 |
3 files changed, 91 insertions, 42 deletions
diff --git a/internal/domain/domain.go b/internal/domain/domain.go index 1455d436..4ce8a561 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "mime" - "net" "net/http" "os" "path/filepath" @@ -17,6 +16,7 @@ import ( "golang.org/x/sys/unix" + "gitlab.com/gitlab-org/gitlab-pages/internal/host" "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" "gitlab.com/gitlab-org/gitlab-pages/internal/httputil" ) @@ -106,16 +106,6 @@ func handleGZip(w http.ResponseWriter, r *http.Request, fullPath string) string return gzipPath } -func getHost(r *http.Request) string { - host := strings.ToLower(r.Host) - - if splitHost, _, err := net.SplitHostPort(host); err == nil { - host = splitHost - } - - return host -} - // Look up a project inside the domain based on the host and path. Returns the // project and its name (if applicable) func (d *D) getProjectWithSubpath(r *http.Request) (*project, string, string) { @@ -131,7 +121,7 @@ func (d *D) getProjectWithSubpath(r *http.Request) (*project, string, string) { // Since the URL doesn't specify a project (e.g. http://mydomain.gitlab.io), // return the group project if it exists. - if host := getHost(r); host != "" { + if host := host.FromRequest(r); host != "" { if groupProject := d.projects[host]; groupProject != nil { return groupProject, host, strings.Join(split[1:], "/") } @@ -179,6 +169,26 @@ func (d *D) IsAccessControlEnabled(r *http.Request) bool { return false } +// HasAcmeChallenge checks domain directory contains particular acme challenge +func (d *D) HasAcmeChallenge(token string) bool { + if d == nil { + return false + } + + if d.config == nil { + return false + } + + _, err := d.resolvePath(d.projectName, ".well-known/acme-challenge", token) + + // there is an acme challenge on disk + if err == nil { + return true + } + + return false +} + // IsNamespaceProject figures out if the request is to a namespace project func (d *D) IsNamespaceProject(r *http.Request) bool { if d == nil { diff --git a/internal/domain/domain_test.go b/internal/domain/domain_test.go index add9b616..a05dbe7e 100644 --- a/internal/domain/domain_test.go +++ b/internal/domain/domain_test.go @@ -3,7 +3,6 @@ package domain import ( "compress/gzip" "io/ioutil" - "mime" "net/http" "net/http/httptest" "net/url" @@ -15,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" + "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" ) func serveFileOrNotFound(domain *D) http.HandlerFunc { @@ -25,11 +25,6 @@ func serveFileOrNotFound(domain *D) http.HandlerFunc { } } -func assertRedirectTo(t *testing.T, h http.HandlerFunc, method string, url string, values url.Values, expectedURL string) { - assert.HTTPRedirect(t, h, method, url, values) - assert.HTTPBodyContains(t, h, method, url, values, `<a href="//`+expectedURL+`">Found</a>`) -} - func testGroupServeHTTPHost(t *testing.T, host string) { testGroup := &D{ projectName: "", @@ -53,12 +48,12 @@ func testGroupServeHTTPHost(t *testing.T, host string) { assert.HTTPBodyContains(t, serve, "GET", makeURL("/"), nil, "main-dir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/index"), nil, "main-dir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/index.html"), nil, "main-dir") - assertRedirectTo(t, serve, "GET", makeURL("/project"), nil, host+"/project/") + testhelpers.AssertRedirectTo(t, serve, "GET", makeURL("/project"), nil, "//"+host+"/project/") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project/"), nil, "project-subdir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project/index"), nil, "project-subdir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project/index/"), nil, "project-subdir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project/index.html"), nil, "project-subdir") - assertRedirectTo(t, serve, "GET", makeURL("/project/subdir"), nil, host+"/project/subdir/") + testhelpers.AssertRedirectTo(t, serve, "GET", makeURL("/project/subdir"), nil, "//"+host+"/project/subdir/") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project/subdir/"), nil, "project-subsubdir") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project2/"), nil, "project2-main") assert.HTTPBodyContains(t, serve, "GET", makeURL("/project2/index"), nil, "project2-main") @@ -205,7 +200,61 @@ func TestIsHTTPSOnly(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, test.url, nil) - assert.Equal(t, test.domain.IsHTTPSOnly(req), test.expected) + assert.Equal(t, test.expected, test.domain.IsHTTPSOnly(req)) + }) + } +} + +func TestHasAcmeChallenge(t *testing.T) { + cleanup := setUpTests(t) + defer cleanup() + + tests := []struct { + name string + domain *D + token string + expected bool + }{ + { + name: "Project containing acme challenge", + domain: &D{ + group: group{name: "group.acme"}, + projectName: "with.acme.challenge", + config: &domainConfig{HTTPSOnly: true}, + }, + token: "existingtoken", + expected: true, + }, + { + name: "Project containing another token", + domain: &D{ + group: group{name: "group.acme"}, + projectName: "with.acme.challenge", + config: &domainConfig{HTTPSOnly: true}, + }, + token: "notexistingtoken", + expected: false, + }, + { + name: "nil domain", + domain: nil, + token: "existingtoken", + expected: false, + }, + { + name: "Domain without config", + domain: &D{ + group: group{name: "group.acme"}, + projectName: "with.acme.challenge", + config: nil, + }, + token: "existingtoken", + expected: false, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, test.domain.HasAcmeChallenge(test.token)) }) } } @@ -304,18 +353,6 @@ func TestGroupServeHTTPGzip(t *testing.T) { } } -func testHTTP404(t *testing.T, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) { - w := httptest.NewRecorder() - req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil) - require.NoError(t, err) - handler(w, req) - - contentType, _, _ := mime.ParseMediaType(w.Header().Get("Content-Type")) - assert.Equal(t, http.StatusNotFound, w.Code, "HTTP status") - assert.Equal(t, "text/html", contentType, "Content-Type") - assert.Contains(t, w.Body.String(), str) -} - func TestGroup404ServeHTTP(t *testing.T) { cleanup := setUpTests(t) defer cleanup() @@ -334,15 +371,15 @@ func TestGroup404ServeHTTP(t *testing.T) { }, } - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.404/not/existing-file", nil, "Custom 404 project page") - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.404/", nil, "Custom 404 project page") - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/not/existing-file", nil, "Custom 404 group page") - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/not-existing-file", nil, "Custom 404 group page") - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/", nil, "Custom 404 group page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.404/not/existing-file", nil, "Custom 404 project page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.404/", nil, "Custom 404 project page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/not/existing-file", nil, "Custom 404 group page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/not-existing-file", nil, "Custom 404 group page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/", nil, "Custom 404 group page") assert.HTTPBodyNotContains(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.404.symlink/not/existing-file", nil, "Custom 404 project page") // Ensure the namespace project's custom 404.html is not used by projects - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.no.404/not/existing-file", nil, "The page you're looking for could not be found.") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.404.test.io/project.no.404/not/existing-file", nil, "The page you're looking for could not be found.") } func TestDomain404ServeHTTP(t *testing.T) { @@ -357,8 +394,8 @@ func TestDomain404ServeHTTP(t *testing.T) { }, } - testHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.404.test.io/not-existing-file", nil, "Custom 404 group page") - testHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.404.test.io/", nil, "Custom 404 group page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.404.test.io/not-existing-file", nil, "Custom 404 group page") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.404.test.io/", nil, "Custom 404 group page") } func TestPredefined404ServeHTTP(t *testing.T) { @@ -369,7 +406,7 @@ func TestPredefined404ServeHTTP(t *testing.T) { group: group{name: "group"}, } - testHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.test.io/not-existing-file", nil, "The page you're looking for could not be found") + testhelpers.AssertHTTP404(t, serveFileOrNotFound(testDomain), "GET", "http://group.test.io/not-existing-file", nil, "The page you're looking for could not be found") } func TestGroupCertificate(t *testing.T) { diff --git a/internal/domain/map_test.go b/internal/domain/map_test.go index dc5e8648..156b039f 100644 --- a/internal/domain/map_test.go +++ b/internal/domain/map_test.go @@ -55,6 +55,8 @@ func TestReadProjects(t *testing.T) { "no.cert.com", "private.domain.com", "group.auth.test.io", + "group.acme.test.io", + "withacmechallenge.domain.com", "capitalgroup.test.io", } |