mattermost-community-enterp.../channels/app/plugin_requests_test.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

622 lines
22 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/v8/channels/testlib"
"github.com/mattermost/mattermost/server/v8/channels/utils/fileutils"
)
func TestServePluginPublicRequest(t *testing.T) {
installPlugin := func(t *testing.T, th *TestHelper, pluginID string) {
t.Helper()
path, _ := fileutils.FindDir("tests")
fileReader, err := os.Open(filepath.Join(path, fmt.Sprintf("%s.tar.gz", pluginID)))
require.NoError(t, err)
defer fileReader.Close()
_, appErr := th.App.WriteFile(fileReader, getBundleStorePath(pluginID))
checkNoError(t, appErr)
appErr = th.App.SyncPlugins()
checkNoError(t, appErr)
env := th.App.GetPluginsEnvironment()
require.NotNil(t, env)
// Check if installed
pluginStatus, err := env.Statuses()
require.NoError(t, err)
found := false
for _, pluginStatus := range pluginStatus {
if pluginStatus.PluginId == pluginID {
found = true
}
}
require.True(t, found, "failed to find plugin %s in plugin statuses", pluginID)
appErr = th.App.EnablePlugin(pluginID)
checkNoError(t, appErr)
t.Cleanup(func() {
appErr = th.App.ch.RemovePlugin(pluginID)
checkNoError(t, appErr)
})
}
t.Run("returns not found when plugins environment is nil", func(t *testing.T) {
th := Setup(t)
t.Cleanup(th.TearDown)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
req, err := http.NewRequest(http.MethodGet, "/plugins/plugin_id/public/file.txt", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(th.App.ch.ServePluginPublicRequest)
handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusNotFound, rr.Code)
})
t.Run("resolves path for valid plugin", func(t *testing.T) {
th := Setup(t)
t.Cleanup(th.TearDown)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
path, _ := fileutils.FindDir("tests")
fileReader, err := os.Open(filepath.Join(path, "testplugin.tar.gz"))
require.NoError(t, err)
defer fileReader.Close()
installPlugin(t, th, "testplugin")
req, err := http.NewRequest(http.MethodGet, "/plugins/testplugin/public/file.txt", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
th.App.ch.srv.Router.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
body, err := io.ReadAll(rr.Body)
require.NoError(t, err)
require.Equal(t, "Hello World!", string(body))
})
t.Run("resolves path for valid plugin when subpath configured", func(t *testing.T) {
os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://localhost:8065/subpath")
defer os.Unsetenv("MM_SERVICESETTINGS_SITEURL")
th := Setup(t)
t.Cleanup(th.TearDown)
installPlugin(t, th, "testplugin")
req, err := http.NewRequest(http.MethodGet, "/subpath/plugins/testplugin/public/file.txt", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
th.App.ch.srv.RootRouter.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
body, err := io.ReadAll(rr.Body)
require.NoError(t, err)
assert.Equal(t, "Hello World!", string(body))
})
t.Run("fails for invalid plugin", func(t *testing.T) {
th := Setup(t)
t.Cleanup(th.TearDown)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
req, err := http.NewRequest(http.MethodGet, "/plugins/invalidplugin/public/file.txt", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
th.App.ch.srv.Router.ServeHTTP(rr, req)
assert.Equal(t, http.StatusNotFound, rr.Code)
})
t.Run("fails attempting to break out of path", func(t *testing.T) {
os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://localhost:8065/subpath")
defer os.Unsetenv("MM_SERVICESETTINGS_SITEURL")
th := Setup(t)
t.Cleanup(th.TearDown)
installPlugin(t, th, "testplugin")
installPlugin(t, th, "testplugin2")
req, err := http.NewRequest(http.MethodGet, "/subpath/plugins/testplugin/public/../../testplugin2/file.txt", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
th.App.ch.srv.RootRouter.ServeHTTP(rr, req)
require.Equal(t, http.StatusMovedPermanently, rr.Code)
assert.Equal(t, "/subpath/plugins/testplugin2/file.txt", rr.Header()["Location"][0])
})
}
// TestUnauthRequestsMFAWarningFix tests the fix for https://mattermost.atlassian.net/browse/MM-63805.
func TestUnauthRequestsMFAWarningFix(t *testing.T) {
th := Setup(t)
defer th.TearDown()
// Enable MFA and require it
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.EnableMultifactorAuthentication = true
*cfg.ServiceSettings.EnforceMultifactorAuthentication = true
})
th.App.Srv().SetLicense(model.NewTestLicense())
// Setup a buffer to capture logs
buffer := &mlog.Buffer{}
err := mlog.AddWriterTarget(th.TestLogger, buffer, true, mlog.StdAll...)
require.NoError(t, err)
// Test the fix by simulating an unauthenticated request (no token at all)
unauthReq := httptest.NewRequest(http.MethodGet, "/plugins/foo/bar", nil)
unauthReq = mux.SetURLVars(unauthReq, map[string]string{"plugin_id": "foo"})
// Handler function for the plugin request
handlerCalled := false
handler := func(_ *plugin.Context, _ http.ResponseWriter, r *http.Request) {
handlerCalled = true
// Verify URL path was properly stripped
require.Equal(t, "/bar", r.URL.Path)
// Verify no user ID header (indicating the request is unauthenticated)
require.Empty(t, r.Header.Get("Mattermost-User-Id"))
}
// Call servePluginRequest directly
th.App.ch.servePluginRequest(nil, unauthReq, handler)
// Verify the handler was actually called
require.True(t, handlerCalled, "Plugin request handler should be called")
// Check the logs for the MFA warning
err = th.TestLogger.Flush()
require.NoError(t, err)
entries := testlib.ParseLogEntries(t, buffer)
for _, e := range entries {
if e.Msg == "Treating session as unauthenticated since MFA required" {
assert.Fail(t, "MFA warning should not be logged for unauthenticated requests")
}
if e.Msg == "Token in plugin request is invalid. Treating request as unauthenticated" {
assert.Fail(t, "MFA warning should not be logged for unauthenticated requests")
}
}
}
func TestServePluginRequest(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic()
defer th.TearDown()
session, err := th.App.CreateSession(th.Context, &model.Session{
UserId: th.BasicUser.Id,
})
require.Nil(t, err)
t.Run("Plugins are disabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
t.Cleanup(func() {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/plugins/foo/bar", nil)
th.App.ch.ServePluginRequest(w, r)
assert.Equal(t, http.StatusNotImplemented, w.Result().StatusCode)
})
t.Run("unauthenticated request", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Empty(t, r.Header.Get("Mattermost-User-Id"))
assert.Empty(t, ctx.SessionId)
assert.NotEmpty(t, ctx.RequestId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("bearer token authentication", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" "+session.Token)
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
// Test again with lower case header prefix
handlerCalled = false
req.Header.Set(model.HeaderAuth, "bearer "+session.Token)
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("token header authentication", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderToken+" "+session.Token)
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
// Test again with upper case header prefix
handlerCalled = false
req.Header.Set(model.HeaderAuth, "TOKEN "+session.Token)
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("cookie authentication", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.AddCookie(&http.Cookie{
Name: model.SessionCookieToken,
Value: session.Token,
})
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("query parameter authentication", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint?access_token="+session.Token, nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
// Verify access_token is removed from query parameters
assert.Empty(t, r.URL.Query().Get("access_token"))
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("invalid token - treats as unauthenticated", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" invalidtoken")
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Empty(t, r.Header.Get("Mattermost-User-Id"))
assert.Empty(t, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("MFA required - treats as unauthenticated", func(t *testing.T) {
// Enable MFA requirement
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.EnableMultifactorAuthentication = true
*cfg.ServiceSettings.EnforceMultifactorAuthentication = true
})
th.App.Srv().SetLicense(model.NewTestLicense())
t.Cleanup(func() {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.EnableMultifactorAuthentication = false
*cfg.ServiceSettings.EnforceMultifactorAuthentication = false
})
})
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" "+session.Token)
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Empty(t, r.Header.Get("Mattermost-User-Id"))
assert.Empty(t, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("header and cookie cleanup", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" "+session.Token)
req.Header.Set("Mattermost-Plugin-ID", "evil-plugin")
req.Header.Set("Mattermost-User-Id", "evil-user")
req.AddCookie(&http.Cookie{Name: "other_cookie", Value: "keep_me"})
req.AddCookie(&http.Cookie{Name: "another_cookie", Value: "keep_me_too"})
req.Header.Set("Referer", "https://evil.com")
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
assert.Empty(t, r.Header.Get("Mattermost-Plugin-ID"))
assert.Empty(t, r.Header.Get(model.HeaderAuth))
assert.Empty(t, r.Header.Get("Referer"))
// Verify that legitimate cookies are preserved (but not session cookies)
cookies := r.Cookies()
cookieNames := make([]string, len(cookies))
for i, cookie := range cookies {
cookieNames[i] = cookie.Name
}
// Session token cookie should be filtered out
assert.NotContains(t, cookieNames, model.SessionCookieToken)
// Other cookies should remain
assert.Contains(t, cookieNames, "other_cookie")
assert.Contains(t, cookieNames, "another_cookie")
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("nested URL path", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/some/deep/path", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
// Path should be stripped of the plugin prefix
assert.Equal(t, "/some/deep/path", r.URL.Path)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("context creation with correct fields", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" "+session.Token)
req.Header.Set("Accept-Language", "en-US,en;q=0.9")
req.Header.Set("User-Agent", "TestAgent/1.0")
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.NotEmpty(t, ctx.RequestId)
assert.NotEmpty(t, ctx.IPAddress)
assert.Equal(t, "en-US,en;q=0.9", ctx.AcceptLanguage)
assert.Equal(t, "TestAgent/1.0", ctx.UserAgent)
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("subpath handling", func(t *testing.T) {
// Set up with subpath
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "http://localhost:8065/subpath" })
t.Cleanup(func() {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "http://localhost:8065" })
})
req := httptest.NewRequest(http.MethodGet, "/subpath/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
// Path should be stripped of both subpath and plugin prefix
assert.Equal(t, "/endpoint", r.URL.Path)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("CSRF validation for cookie auth POST request", func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.AddCookie(&http.Cookie{
Name: model.SessionCookieToken,
Value: session.Token,
})
req.Header.Set(model.HeaderCsrfToken, session.GetCSRF())
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id"))
assert.Equal(t, session.Id, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("CSRF validation fails for cookie auth POST request", func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/plugins/testplugin/endpoint", nil)
req = mux.SetURLVars(req, map[string]string{"plugin_id": "testplugin"})
req.AddCookie(&http.Cookie{
Name: model.SessionCookieToken,
Value: session.Token,
})
req.Header.Set(model.HeaderCsrfToken, "invalid-csrf-token")
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
// Should not have user ID header due to CSRF failure
assert.Empty(t, r.Header.Get("Mattermost-User-Id"))
assert.Empty(t, ctx.SessionId)
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
t.Run("third-party use of Authorization header preserved", func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/plugins/testplugin/endpoint", nil)
req.Header.Set(model.HeaderAuth, "Bearer 3rd-party-token")
rr := httptest.NewRecorder()
handlerCalled := false
mockHandler := func(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
handlerCalled = true
// Should still have the authorization header
assert.Equal(t, "Bearer 3rd-party-token", r.Header.Get(model.HeaderAuth))
}
th.App.ch.servePluginRequest(rr, req, mockHandler)
require.True(t, handlerCalled)
})
}
func TestValidateCSRFForPluginRequest(t *testing.T) {
th := Setup(t)
defer th.TearDown()
t.Run("skip CSRF for non-cookie auth", func(t *testing.T) {
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
session.GenerateCSRF()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
result := validateCSRFForPluginRequest(th.Context, req, session, false, false)
assert.True(t, result)
})
t.Run("skip CSRF for GET requests", func(t *testing.T) {
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
session.GenerateCSRF()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
result := validateCSRFForPluginRequest(th.Context, req, session, true, false)
assert.True(t, result)
})
t.Run("valid CSRF token in header", func(t *testing.T) {
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
expectedToken := session.GenerateCSRF()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
req.Header.Set(model.HeaderCsrfToken, expectedToken)
result := validateCSRFForPluginRequest(th.Context, req, session, true, false)
assert.True(t, result)
})
t.Run("invalid CSRF token in header", func(t *testing.T) {
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
session.GenerateCSRF()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
req.Header.Set(model.HeaderCsrfToken, "invalid-token")
result := validateCSRFForPluginRequest(th.Context, req, session, true, false)
assert.False(t, result)
})
t.Run("valid CSRF token in form data", func(t *testing.T) {
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
expectedToken := session.GetCSRF()
formData := "csrf=" + expectedToken + "&other=value"
req := httptest.NewRequest(http.MethodPost, "/test", strings.NewReader(formData))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
result := validateCSRFForPluginRequest(th.Context, req, session, true, false)
assert.True(t, result)
})
t.Run("XMLHttpRequest with strict enforcement disabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.ExperimentalStrictCSRFEnforcement = false
})
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
session.GenerateCSRF()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
req.Header.Set(model.HeaderRequestedWith, model.HeaderRequestedWithXML)
result := validateCSRFForPluginRequest(th.Context, req, session, true, false)
assert.True(t, result)
})
t.Run("XMLHttpRequest with strict enforcement enabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.ExperimentalStrictCSRFEnforcement = true
})
session := &model.Session{Id: "sessionid", UserId: "userid", Token: "token"}
session.GenerateCSRF()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
req.Header.Set(model.HeaderRequestedWith, model.HeaderRequestedWithXML)
result := validateCSRFForPluginRequest(th.Context, req, session, true, true)
assert.False(t, result)
})
}