From 02337053d128429debec43dd36f2c3b7c141552e Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Wed, 29 Aug 2018 22:00:35 +0200 Subject: [PATCH 1/8] When file not found, possibly redirect to GitLab for acme challenge In case the file is not found, check the path if it is the Let's Encrypt acme challenge path. And if so, redirect to gitlab-rails so it can serve it from the database. This redirect should only happen when a custom domain is visited, not the generic GitLab Pages domain. And also HTTP only, no HTTPS. Closes gitlab-org/gitlab-pages#165 --- internal/domain/domain.go | 20 ++++++++++++++ internal/domain/domain_test.go | 26 +++++++++++++++++++ .../.well-known/acme-challenge/existing-file | 1 + 3 files changed, 47 insertions(+) create mode 100644 shared/pages/group/project2/public/.well-known/acme-challenge/existing-file diff --git a/internal/domain/domain.go b/internal/domain/domain.go index 1455d4368..a3c080007 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -116,6 +116,22 @@ func getHost(r *http.Request) string { return host } +func (d *D) isAcmeChallenge(path string) bool { + // Only allow acme challenges for custom domains + if d.config == nil { + return false + } + return strings.HasPrefix(path, "/.well-known/acme-challenge/") +} + +func setContentType(w http.ResponseWriter, fullPath string) { + ext := filepath.Ext(fullPath) + ctype := mime.TypeByExtension(ext) + if ctype != "" { + w.Header().Set("Content-Type", ctype) + } +} + // 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) { @@ -388,6 +404,10 @@ func (d *D) tryFile(w http.ResponseWriter, r *http.Request, projectName string, if locationError, _ := err.(*locationDirectoryError); locationError != nil { if endsWithSlash(r.URL.Path) { fullPath, err = d.resolvePath(projectName, filepath.Join(subPath...), "index.html") + } else if d.isAcmeChallenge(r.URL.Path) { + redirectPath := "//gitlab.com/-/acme-challenge/" + r.Host + "/" + filepath.Base(r.URL.Path) + http.Redirect(w, r, redirectPath, 301) + return nil } else { // Concat Host with URL.Path redirectPath := "//" + r.Host + "/" diff --git a/internal/domain/domain_test.go b/internal/domain/domain_test.go index add9b616a..a7ad02f00 100644 --- a/internal/domain/domain_test.go +++ b/internal/domain/domain_test.go @@ -471,6 +471,32 @@ func TestOpenNoFollow(t *testing.T) { require.Nil(t, link) } +func TestAcmeChallengeRedirect(t *testing.T) { + setUpTests(t) + + testGroup := &D{ + group: group{name: "group"}, + projectName: "project2", + } + + testDomain := &D{ + group: group{name: "group"}, + projectName: "project2", + config: &domainConfig{ + Domain: "test.example.com", + }, + } + + + testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.test.io/project2/.well-known/acme-challenge/0123456789abcdef", nil, "The page you're looking for could not be found") + assert.HTTPBodyContains(t, serveFileOrNotFound(testGroup), "GET", "http://group.test.io/project2/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") + + assert.HTTPRedirect(t, serveFileOrNotFound(testDomain), "GET", "http://test.example.com/.well-known/acme-challenge/0123456789abcdef", nil) + assert.HTTPBodyContains(t, serveFileOrNotFound(testDomain), "GET", "http://test.example.com/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") + testHTTP404(t, serveFileOrNotFound(testDomain), "GET", "https://test.example.com/.well-known/acme-challenge/0123456789abcdef", nil, "The page you're looking for could not be found") + assert.HTTPBodyContains(t, serveFileOrNotFound(testDomain), "GET", "https://test.example.com/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") +} + var chdirSet = false func setUpTests(t require.TestingT) func() { diff --git a/shared/pages/group/project2/public/.well-known/acme-challenge/existing-file b/shared/pages/group/project2/public/.well-known/acme-challenge/existing-file new file mode 100644 index 000000000..dc6b3d555 --- /dev/null +++ b/shared/pages/group/project2/public/.well-known/acme-challenge/existing-file @@ -0,0 +1 @@ +Yes, I really exist \ No newline at end of file -- GitLab From 8478415c286c52c4c1da34eca4eb14f20f9f6126 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Fri, 22 Mar 2019 13:48:08 +0300 Subject: [PATCH 2/8] Fix domain tests * change cleanup to defered version * change group config to newer format I'm not sure about this, I copied it from another test --- internal/domain/domain_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/domain/domain_test.go b/internal/domain/domain_test.go index a7ad02f00..2d7b5adf1 100644 --- a/internal/domain/domain_test.go +++ b/internal/domain/domain_test.go @@ -472,22 +472,27 @@ func TestOpenNoFollow(t *testing.T) { } func TestAcmeChallengeRedirect(t *testing.T) { - setUpTests(t) + cleanup := setUpTests(t) + defer cleanup() testGroup := &D{ - group: group{name: "group"}, - projectName: "project2", + projectName: "", + group: group{ + name: "group", + projects: map[string]*project{ + "project2": &project{}, + }, + }, } testDomain := &D{ group: group{name: "group"}, projectName: "project2", config: &domainConfig{ - Domain: "test.example.com", + Domain: "test.example.com", }, } - testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.test.io/project2/.well-known/acme-challenge/0123456789abcdef", nil, "The page you're looking for could not be found") assert.HTTPBodyContains(t, serveFileOrNotFound(testGroup), "GET", "http://group.test.io/project2/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") -- GitLab From 6ae6e6542f323fcfdfb4a99af2a2a8d1f9dbe76c Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Fri, 22 Mar 2019 13:56:37 +0300 Subject: [PATCH 3/8] Change 301 redirect to 302 for acme challenges --- internal/domain/domain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/domain/domain.go b/internal/domain/domain.go index a3c080007..efac6a6b9 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -406,7 +406,7 @@ func (d *D) tryFile(w http.ResponseWriter, r *http.Request, projectName string, fullPath, err = d.resolvePath(projectName, filepath.Join(subPath...), "index.html") } else if d.isAcmeChallenge(r.URL.Path) { redirectPath := "//gitlab.com/-/acme-challenge/" + r.Host + "/" + filepath.Base(r.URL.Path) - http.Redirect(w, r, redirectPath, 301) + http.Redirect(w, r, redirectPath, 302) return nil } else { // Concat Host with URL.Path -- GitLab From cef7cf9f77d2d7704775bff7c0d5723ee0df898b Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Mon, 25 Mar 2019 12:26:18 +0300 Subject: [PATCH 4/8] Redirect to gitlab for acme challenges --- internal/domain/domain.go | 23 ++++++++++++++++++----- internal/domain/domain_test.go | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/internal/domain/domain.go b/internal/domain/domain.go index efac6a6b9..e03724ee4 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -17,6 +17,8 @@ import ( "golang.org/x/sys/unix" + log "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" "gitlab.com/gitlab-org/gitlab-pages/internal/httputil" ) @@ -402,12 +404,10 @@ func (d *D) tryFile(w http.ResponseWriter, r *http.Request, projectName string, fullPath, err := d.resolvePath(projectName, subPath...) if locationError, _ := err.(*locationDirectoryError); locationError != nil { + log.WithField("file", locationError.FullPath).Debug("File not found") if endsWithSlash(r.URL.Path) { + log.Debug("Try to serve index.html") fullPath, err = d.resolvePath(projectName, filepath.Join(subPath...), "index.html") - } else if d.isAcmeChallenge(r.URL.Path) { - redirectPath := "//gitlab.com/-/acme-challenge/" + r.Host + "/" + filepath.Base(r.URL.Path) - http.Redirect(w, r, redirectPath, 302) - return nil } else { // Concat Host with URL.Path redirectPath := "//" + r.Host + "/" @@ -425,6 +425,7 @@ func (d *D) tryFile(w http.ResponseWriter, r *http.Request, projectName string, } if err != nil { + log.WithError(err).Debug("Cant resolve path") return err } @@ -462,8 +463,20 @@ func (d *D) serveNotFoundFromGroup(w http.ResponseWriter, r *http.Request) { } func (d *D) serveFileFromConfig(w http.ResponseWriter, r *http.Request) bool { + log.WithFields(log.Fields{ + "project_name": d.projectName, + "path": r.URL.Path, + }).Debug("Serving file from config") // Try to serve file for http://host/... => /group/project/... - if d.tryFile(w, r, d.projectName, r.URL.Path) == nil { + err := d.tryFile(w, r, d.projectName, r.URL.Path) + if err == nil { + return true + } + + if err != nil && d.isAcmeChallenge(r.URL.Path) { + log.Debug("Get request for acme-challenge, redirecting to gitlab instance") + redirectPath := "//gitlab.com/-/acme-challenge/" + r.Host + "/" + filepath.Base(r.URL.Path) + http.Redirect(w, r, redirectPath, 302) return true } diff --git a/internal/domain/domain_test.go b/internal/domain/domain_test.go index 2d7b5adf1..a6e3fa70d 100644 --- a/internal/domain/domain_test.go +++ b/internal/domain/domain_test.go @@ -498,7 +498,7 @@ func TestAcmeChallengeRedirect(t *testing.T) { assert.HTTPRedirect(t, serveFileOrNotFound(testDomain), "GET", "http://test.example.com/.well-known/acme-challenge/0123456789abcdef", nil) assert.HTTPBodyContains(t, serveFileOrNotFound(testDomain), "GET", "http://test.example.com/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") - testHTTP404(t, serveFileOrNotFound(testDomain), "GET", "https://test.example.com/.well-known/acme-challenge/0123456789abcdef", nil, "The page you're looking for could not be found") + assert.HTTPRedirect(t, serveFileOrNotFound(testDomain), "GET", "https://test.example.com/.well-known/acme-challenge/0123456789abcdef", nil) assert.HTTPBodyContains(t, serveFileOrNotFound(testDomain), "GET", "https://test.example.com/.well-known/acme-challenge/existing-file", nil, "Yes, I really exist") } -- GitLab From e8b175c897d74e9b701880bd33d62ad9088afe10 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 28 Mar 2019 13:34:57 +0300 Subject: [PATCH 5/8] Extract config into separate package --- app.go | 9 +++++---- daemon.go | 7 ++++--- app_config.go => internal/config/config.go | 5 +++-- main.go | 16 +++++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) rename app_config.go => internal/config/config.go (88%) diff --git a/app.go b/app.go index b872a6a1e..420d4f709 100644 --- a/app.go +++ b/app.go @@ -20,6 +20,7 @@ import ( "gitlab.com/gitlab-org/gitlab-pages/internal/admin" "gitlab.com/gitlab-org/gitlab-pages/internal/artifact" "gitlab.com/gitlab-org/gitlab-pages/internal/auth" + "gitlab.com/gitlab-org/gitlab-pages/internal/config" "gitlab.com/gitlab-org/gitlab-pages/internal/domain" "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" "gitlab.com/gitlab-org/gitlab-pages/internal/netutil" @@ -37,7 +38,7 @@ var ( ) type theApp struct { - appConfig + config.Config dm domain.Map lock sync.RWMutex Artifact *artifact.Artifact @@ -123,7 +124,7 @@ func (a *theApp) checkAuthenticationIfNotExists(domain *domain.D, w http.Respons func (a *theApp) tryAuxiliaryHandlers(w http.ResponseWriter, r *http.Request, https bool, host string, domain *domain.D) bool { // short circuit content serving to check for a status page - if r.RequestURI == a.appConfig.StatusPath { + if r.RequestURI == a.Config.StatusPath { a.healthCheck(w, r, https) return true } @@ -353,8 +354,8 @@ func (a *theApp) listenAdminHTTPS(wg *sync.WaitGroup) { }() } -func runApp(config appConfig) { - a := theApp{appConfig: config} +func runApp(config config.Config) { + a := theApp{Config: config} if config.ArtifactsServer != "" { a.Artifact = artifact.New(config.ArtifactsServer, config.ArtifactsServerTimeout, config.Domain) diff --git a/daemon.go b/daemon.go index 2b3cc8c6c..1ce567ac8 100644 --- a/daemon.go +++ b/daemon.go @@ -12,6 +12,7 @@ import ( "github.com/kardianos/osext" log "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/gitlab-pages/internal/config" "gitlab.com/gitlab-org/gitlab-pages/internal/jail" ) @@ -32,7 +33,7 @@ func daemonMain() { }).Info("starting the daemon as unprivileged user") // read the configuration from the pipe "ExtraFiles" - var config appConfig + var config config.Config if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&config); err != nil { fatal(err) } @@ -199,7 +200,7 @@ func jailDaemon(cmd *exec.Cmd) (*jail.Jail, error) { return cage, nil } -func daemonize(config appConfig, uid, gid uint, inPlace bool) error { +func daemonize(config config.Config, uid, gid uint, inPlace bool) error { log.WithFields(log.Fields{ "uid": uid, "gid": gid, @@ -260,7 +261,7 @@ func daemonize(config appConfig, uid, gid uint, inPlace bool) error { return cmd.Wait() } -func updateFds(config *appConfig, cmd *exec.Cmd) { +func updateFds(config *config.Config, cmd *exec.Cmd) { for _, fds := range [][]uintptr{ config.ListenHTTP, config.ListenHTTPS, diff --git a/app_config.go b/internal/config/config.go similarity index 88% rename from app_config.go rename to internal/config/config.go index 9ff26b6b9..f41619b6a 100644 --- a/app_config.go +++ b/internal/config/config.go @@ -1,6 +1,7 @@ -package main +package config -type appConfig struct { +// Config contains main configuration variables +type Config struct { Domain string ArtifactsServer string ArtifactsServerTimeout int diff --git a/main.go b/main.go index 126ad69ed..887282395 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,8 @@ import ( "github.com/namsral/flag" log "github.com/sirupsen/logrus" + + "gitlab.com/gitlab-org/gitlab-pages/internal/config" ) // VERSION stores the information about the semantic version of application @@ -71,8 +73,8 @@ var ( errRedirectURINotDefined = errors.New("auth-redirect-uri must be defined if authentication is supported") ) -func configFromFlags() appConfig { - var config appConfig +func configFromFlags() config.Config { + var config config.Config config.Domain = strings.ToLower(*pagesDomain) config.RedirectHTTP = *redirectHTTP @@ -131,7 +133,7 @@ func configFromFlags() appConfig { return config } -func checkAuthenticationConfig(config appConfig) { +func checkAuthenticationConfig(config config.Config) { if *secret != "" || *clientID != "" || *clientSecret != "" || *gitLabServer != "" || *redirectURI != "" { // Check all auth params are valid @@ -243,7 +245,7 @@ func closeAll(cs []io.Closer) { // createAppListeners returns net.Listener and *os.File instances. The // caller must ensure they don't get closed or garbage-collected (which // implies closing) too soon. -func createAppListeners(config *appConfig) []io.Closer { +func createAppListeners(config *config.Config) []io.Closer { var closers []io.Closer for _, addr := range listenHTTP.Split() { @@ -285,7 +287,7 @@ func createAppListeners(config *appConfig) []io.Closer { // createMetricsListener returns net.Listener and *os.File instances. The // caller must ensure they don't get closed or garbage-collected (which // implies closing) too soon. -func createMetricsListener(config *appConfig) []io.Closer { +func createMetricsListener(config *config.Config) []io.Closer { addr := *metricsAddress if addr == "" { return nil @@ -304,7 +306,7 @@ func createMetricsListener(config *appConfig) []io.Closer { // createAdminUnixListener returns net.Listener and *os.File instances. The // caller must ensure they don't get closed or garbage-collected (which // implies closing) too soon. -func createAdminUnixListener(config *appConfig) []io.Closer { +func createAdminUnixListener(config *config.Config) []io.Closer { unixPath := *adminUnixListener if unixPath == "" { return nil @@ -327,7 +329,7 @@ func createAdminUnixListener(config *appConfig) []io.Closer { // createAdminHTTPSListener returns net.Listener and *os.File instances. The // caller must ensure they don't get closed or garbage-collected (which // implies closing) too soon. -func createAdminHTTPSListener(config *appConfig) []io.Closer { +func createAdminHTTPSListener(config *config.Config) []io.Closer { addr := *adminHTTPSListener if addr == "" { return nil -- GitLab From 1b0a42be44f024334f978f3a4f803cc74a3211d1 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 28 Mar 2019 14:14:14 +0300 Subject: [PATCH 6/8] Disable access-control for acme-challenges --- app.go | 2 +- internal/domain/domain.go | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app.go b/app.go index 420d4f709..d94613ac1 100644 --- a/app.go +++ b/app.go @@ -176,7 +176,7 @@ func (a *theApp) serveContent(ww http.ResponseWriter, r *http.Request, https boo } // Only for projects that have access control enabled - if domain.IsAccessControlEnabled(r) { + if domain.IsResourceProtected(r) { log.WithFields(log.Fields{ "host": r.Host, "path": r.RequestURI, diff --git a/internal/domain/domain.go b/internal/domain/domain.go index e03724ee4..cc02bfd39 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -178,12 +178,16 @@ func (d *D) IsHTTPSOnly(r *http.Request) bool { return false } -// IsAccessControlEnabled figures out if the request is to a project that has access control enabled -func (d *D) IsAccessControlEnabled(r *http.Request) bool { +// IsResourceProtected figures out if the request is to a project that has access control enabled +func (d *D) IsResourceProtected(r *http.Request) bool { if d == nil { return false } + if d.isAcmeChallenge(r.URL.Path) { + return false + } + // Check custom domain config (e.g. http://example.com) if d.config != nil { return d.config.AccessControl @@ -291,7 +295,7 @@ func (d *D) serveFile(w http.ResponseWriter, r *http.Request, origPath string) e return err } - if !d.IsAccessControlEnabled(r) { + if !d.IsResourceProtected(r) { // Set caching headers w.Header().Set("Cache-Control", "max-age=600") w.Header().Set("Expires", time.Now().Add(10*time.Minute).Format(time.RFC1123)) -- GitLab From bb2af7ea515177b56c88c57ed03c2a76b4f74876 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 28 Mar 2019 14:51:50 +0300 Subject: [PATCH 7/8] Pass application config down to domain config --- app.go | 2 +- internal/domain/domain.go | 3 +++ internal/domain/map.go | 16 +++++++++------- internal/domain/map_test.go | 10 ++++++---- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index d94613ac1..c03397f0e 100644 --- a/app.go +++ b/app.go @@ -300,7 +300,7 @@ func (a *theApp) Run() { a.listenAdminUnix(&wg) a.listenAdminHTTPS(&wg) - go domain.Watch(a.Domain, a.UpdateDomains, time.Second) + go domain.Watch(a.Domain, a.UpdateDomains, time.Second, &a.Config) wg.Wait() } diff --git a/internal/domain/domain.go b/internal/domain/domain.go index cc02bfd39..3592be141 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -19,6 +19,7 @@ import ( log "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/gitlab-pages/internal/config" "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" "gitlab.com/gitlab-org/gitlab-pages/internal/httputil" ) @@ -58,6 +59,8 @@ type D struct { certificate *tls.Certificate certificateError error certificateOnce sync.Once + + appConfig *config.Config } // String implements Stringer. diff --git a/internal/domain/map.go b/internal/domain/map.go index 2891a272a..64a8e3347 100644 --- a/internal/domain/map.go +++ b/internal/domain/map.go @@ -12,6 +12,7 @@ import ( "github.com/karrick/godirwalk" log "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/gitlab-pages/internal/config" "gitlab.com/gitlab-org/gitlab-pages/metrics" ) @@ -34,11 +35,12 @@ func (dm Map) updateDomainMap(domainName string, domain *D) { dm[domainName] = domain } -func (dm Map) addDomain(rootDomain, groupName, projectName string, config *domainConfig) { +func (dm Map) addDomain(rootDomain, groupName, projectName string, config *domainConfig, appConfig *config.Config) { newDomain := &D{ group: group{name: groupName}, projectName: projectName, config: config, + appConfig: appConfig, } var domainName string @@ -89,7 +91,7 @@ func (dm Map) updateGroupDomain(rootDomain, groupName, projectPath string, https dm[domainName] = groupDomain } -func (dm Map) readProjectConfig(rootDomain string, group, projectName string, config *domainsConfig) { +func (dm Map) readProjectConfig(rootDomain string, group, projectName string, config *domainsConfig, appConfig *config.Config) { if config == nil { // This is necessary to preserve the previous behaviour where a // group domain is created even if no config.json files are @@ -103,7 +105,7 @@ func (dm Map) readProjectConfig(rootDomain string, group, projectName string, co for _, domainConfig := range config.Domains { config := domainConfig // domainConfig is reused for each loop iteration if domainConfig.Valid(rootDomain) { - dm.addDomain(rootDomain, group, projectName, &config) + dm.addDomain(rootDomain, group, projectName, &config, appConfig) } } } @@ -167,7 +169,7 @@ type jobResult struct { } // ReadGroups walks the pages directory and populates dm with all the domains it finds. -func (dm Map) ReadGroups(rootDomain string, fis godirwalk.Dirents) { +func (dm Map) ReadGroups(rootDomain string, fis godirwalk.Dirents, appConfig *config.Config) { fanOutGroups := make(chan string) fanIn := make(chan jobResult) wg := &sync.WaitGroup{} @@ -200,7 +202,7 @@ func (dm Map) ReadGroups(rootDomain string, fis godirwalk.Dirents) { done := make(chan struct{}) go func() { for result := range fanIn { - dm.readProjectConfig(rootDomain, result.group, result.project, result.config) + dm.readProjectConfig(rootDomain, result.group, result.project, result.config, appConfig) } close(done) @@ -225,7 +227,7 @@ const ( ) // Watch polls the filesystem and kicks off a new domain directory scan when needed. -func Watch(rootDomain string, updater domainsUpdater, interval time.Duration) { +func Watch(rootDomain string, updater domainsUpdater, interval time.Duration, appConfig *config.Config) { lastUpdate := []byte("no-update") for { @@ -254,7 +256,7 @@ func Watch(rootDomain string, updater domainsUpdater, interval time.Duration) { continue } - dm.ReadGroups(rootDomain, fis) + dm.ReadGroups(rootDomain, fis, appConfig) duration := time.Since(started).Seconds() var hash string diff --git a/internal/domain/map_test.go b/internal/domain/map_test.go index dc5e8648d..a848e5bf0 100644 --- a/internal/domain/map_test.go +++ b/internal/domain/map_test.go @@ -12,6 +12,8 @@ import ( "github.com/karrick/godirwalk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "gitlab.com/gitlab-org/gitlab-pages/internal/config" ) func getEntries(t *testing.T) godirwalk.Dirents { @@ -35,7 +37,7 @@ func TestReadProjects(t *testing.T) { defer cleanup() dm := make(Map) - dm.ReadGroups("test.io", getEntries(t)) + dm.ReadGroups("test.io", getEntries(t), &config.Config{}) var domains []string for d := range dm { @@ -90,7 +92,7 @@ func TestReadProjectsMaxDepth(t *testing.T) { defaultDomain := "test.io" dm := make(Map) - dm.ReadGroups(defaultDomain, getEntries(t)) + dm.ReadGroups(defaultDomain, getEntries(t), &config.Config{}) var domains []string for d := range dm { @@ -158,7 +160,7 @@ func TestWatch(t *testing.T) { update := make(chan Map) go Watch("gitlab.io", func(dm Map) { update <- dm - }, time.Microsecond*50) + }, time.Microsecond*50, &config.Config{}) defer os.Remove(updateFile) @@ -233,7 +235,7 @@ func BenchmarkReadGroups(b *testing.B) { var dm Map for i := 0; i < 2; i++ { dm = make(Map) - dm.ReadGroups("example.com", getEntriesForBenchmark(b)) + dm.ReadGroups("example.com", getEntriesForBenchmark(b), &config.Config{}) } b.Logf("found %d domains", len(dm)) }) -- GitLab From 95d4077f3bd840a7e56e6b85e0bbe0b00ed57b44 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 28 Mar 2019 15:22:54 +0300 Subject: [PATCH 8/8] Use artifacts server as host for acme challenges --- internal/domain/domain.go | 26 ++++++++++++++++++++++---- internal/domain/domain_test.go | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/domain/domain.go b/internal/domain/domain.go index 3592be141..b245da20e 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -8,6 +8,7 @@ import ( "mime" "net" "net/http" + "net/url" "os" "path/filepath" "strconv" @@ -129,6 +130,26 @@ func (d *D) isAcmeChallenge(path string) bool { return strings.HasPrefix(path, "/.well-known/acme-challenge/") } +// This should be moved to additional config param +func (d *D) gitlabServer() string { + url, err := url.Parse(d.appConfig.ArtifactsServer) + if err != nil { + return "" + } + host, _, _ := net.SplitHostPort(url.Host) + return host +} + +func (d *D) redirectForAcmeChallenge(w http.ResponseWriter, r *http.Request) bool { + log.Debug("Get request for acme-challenge, redirecting to gitlab instance") + + host := getHost(r) + redirectPath := "//" + d.gitlabServer() + "/-/acme-challenge/" + host + "/" + filepath.Base(r.URL.Path) + http.Redirect(w, r, redirectPath, 302) + return true + +} + func setContentType(w http.ResponseWriter, fullPath string) { ext := filepath.Ext(fullPath) ctype := mime.TypeByExtension(ext) @@ -481,10 +502,7 @@ func (d *D) serveFileFromConfig(w http.ResponseWriter, r *http.Request) bool { } if err != nil && d.isAcmeChallenge(r.URL.Path) { - log.Debug("Get request for acme-challenge, redirecting to gitlab instance") - redirectPath := "//gitlab.com/-/acme-challenge/" + r.Host + "/" + filepath.Base(r.URL.Path) - http.Redirect(w, r, redirectPath, 302) - return true + d.redirectForAcmeChallenge(w, r) } return false diff --git a/internal/domain/domain_test.go b/internal/domain/domain_test.go index a6e3fa70d..0269e3e5a 100644 --- a/internal/domain/domain_test.go +++ b/internal/domain/domain_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitlab-pages/internal/config" "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" ) @@ -491,6 +492,7 @@ func TestAcmeChallengeRedirect(t *testing.T) { config: &domainConfig{ Domain: "test.example.com", }, + appConfig: &config.Config{ArtifactsServer: "example.com"}, } testHTTP404(t, serveFileOrNotFound(testGroup), "GET", "http://group.test.io/project2/.well-known/acme-challenge/0123456789abcdef", nil, "The page you're looking for could not be found") -- GitLab