From bae26ec268aef4e85d5055f1b83c6b3992bf178f Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 26 Jul 2018 08:31:22 -0700 Subject: MM-11160 Adding proper CORS support. (#9152) * Adding proper CORS support. * Better CORS tests. --- api4/apitestlib.go | 13 +++-- api4/cors_test.go | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 api4/cors_test.go (limited to 'api4') diff --git a/api4/apitestlib.go b/api4/apitestlib.go index ff7d47b26..fce44cfa1 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -75,7 +75,7 @@ func StopTestStore() { } } -func setupTestHelper(enterprise bool) *TestHelper { +func setupTestHelper(enterprise bool, updateConfig func(*model.Config)) *TestHelper { permConfig, err := os.Open(utils.FindConfigFile("config.json")) if err != nil { panic(err) @@ -115,6 +115,9 @@ func setupTestHelper(enterprise bool) *TestHelper { if testStore != nil { th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" }) } + if updateConfig != nil { + th.App.UpdateConfig(updateConfig) + } serverErr := th.App.StartServer() if serverErr != nil { panic(serverErr) @@ -161,11 +164,15 @@ func setupTestHelper(enterprise bool) *TestHelper { } func SetupEnterprise() *TestHelper { - return setupTestHelper(true) + return setupTestHelper(true, nil) } func Setup() *TestHelper { - return setupTestHelper(false) + return setupTestHelper(false, nil) +} + +func SetupConfig(updateConfig func(cfg *model.Config)) *TestHelper { + return setupTestHelper(false, updateConfig) } func (me *TestHelper) TearDown() { diff --git a/api4/cors_test.go b/api4/cors_test.go new file mode 100644 index 000000000..74702b284 --- /dev/null +++ b/api4/cors_test.go @@ -0,0 +1,150 @@ +package api4 + +import ( + "fmt" + "net/http" + "testing" + + "github.com/mattermost/mattermost-server/model" + "github.com/stretchr/testify/assert" +) + +const ( + acAllowOrigin = "Access-Control-Allow-Origin" + acExposeHeaders = "Access-Control-Expose-Headers" + acMaxAge = "Access-Control-Max-Age" + acAllowCredentials = "Access-Control-Allow-Credentials" + acAllowMethods = "Access-Control-Allow-Methods" + acAllowHeaders = "Access-Control-Allow-Headers" +) + +func TestCORSRequestHandling(t *testing.T) { + for name, testcase := range map[string]struct { + AllowCorsFrom string + CorsExposedHeaders string + CorsAllowCredentials bool + ModifyRequest func(req *http.Request) + ExpectedAllowOrigin string + ExpectedExposeHeaders string + ExpectedAllowCredentials string + }{ + "NoCORS": { + "", + "", + false, + func(req *http.Request) { + }, + "", + "", + "", + }, + "CORSEnabled": { + "http://somewhere.com", + "", + false, + func(req *http.Request) { + }, + "", + "", + "", + }, + "CORSEnabledStarOrigin": { + "*", + "", + false, + func(req *http.Request) { + req.Header.Set("Origin", "http://pre-release.mattermost.com") + }, + "*", + "", + "", + }, + "CORSEnabledStarNoOrigin": { // CORS spec requires this, not a bug. + "*", + "", + false, + func(req *http.Request) { + }, + "", + "", + "", + }, + "CORSEnabledMatching": { + "http://mattermost.com", + "", + false, + func(req *http.Request) { + req.Header.Set("Origin", "http://mattermost.com") + }, + "http://mattermost.com", + "", + "", + }, + "CORSEnabledMultiple": { + "http://spinmint.com http://mattermost.com", + "", + false, + func(req *http.Request) { + req.Header.Set("Origin", "http://mattermost.com") + }, + "http://mattermost.com", + "", + "", + }, + "CORSEnabledWithCredentials": { + "http://mattermost.com", + "", + true, + func(req *http.Request) { + req.Header.Set("Origin", "http://mattermost.com") + }, + "http://mattermost.com", + "", + "true", + }, + "CORSEnabledWithHeaders": { + "http://mattermost.com", + "x-my-special-header x-blueberry", + true, + func(req *http.Request) { + req.Header.Set("Origin", "http://mattermost.com") + }, + "http://mattermost.com", + "X-My-Special-Header, X-Blueberry", + "true", + }, + } { + t.Run(name, func(t *testing.T) { + th := SetupConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.AllowCorsFrom = testcase.AllowCorsFrom + *cfg.ServiceSettings.CorsExposedHeaders = testcase.CorsExposedHeaders + *cfg.ServiceSettings.CorsAllowCredentials = testcase.CorsAllowCredentials + }) + defer th.TearDown() + + port := th.App.Srv.ListenAddr.Port + host := fmt.Sprintf("http://localhost:%v", port) + url := fmt.Sprintf("%v/api/v4/system/ping", host) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatal(err) + } + testcase.ModifyRequest(req) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, testcase.ExpectedAllowOrigin, resp.Header.Get(acAllowOrigin)) + assert.Equal(t, testcase.ExpectedExposeHeaders, resp.Header.Get(acExposeHeaders)) + assert.Equal(t, "", resp.Header.Get(acMaxAge)) + assert.Equal(t, testcase.ExpectedAllowCredentials, resp.Header.Get(acAllowCredentials)) + assert.Equal(t, "", resp.Header.Get(acAllowMethods)) + assert.Equal(t, "", resp.Header.Get(acAllowHeaders)) + }) + } + +} -- cgit v1.2.3-1-g7c22