MM-15889 Add unit tests for CSRF checks (#11058)
* MM-15889 Add unit tests for CSRF checks * Moved CSRF token test to login tests * Remove empty test * Remove debug messages
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
28cf642ccb
Коммит
803ce61ef8
@@ -515,7 +515,6 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if action == model.OAUTH_ACTION_EMAIL_TO_SSO {
|
||||
redirectUrl = c.GetSiteURLHeader() + "/login?extra=signin_change"
|
||||
} else if action == model.OAUTH_ACTION_SSO_TO_EMAIL {
|
||||
|
||||
redirectUrl = app.GetProtocol(r) + "://" + r.Host + "/claim?email=" + url.QueryEscape(props["email"])
|
||||
} else {
|
||||
session, err := c.App.DoLogin(w, r, user, "")
|
||||
@@ -528,6 +527,8 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
c.App.AttachSessionCookies(w, r, session)
|
||||
|
||||
c.App.Session = *session
|
||||
|
||||
if _, ok := props["redirect_to"]; ok {
|
||||
|
||||
@@ -1341,6 +1341,10 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
c.LogAuditWithUserId(user.Id, "success")
|
||||
|
||||
if r.Header.Get(model.HEADER_REQUESTED_WITH) == model.HEADER_REQUESTED_WITH_XML {
|
||||
c.App.AttachSessionCookies(w, r, session)
|
||||
}
|
||||
|
||||
userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
|
||||
if err != nil && err.StatusCode != http.StatusNotFound {
|
||||
c.Err = err
|
||||
|
||||
@@ -6,6 +6,7 @@ package api4
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -32,22 +33,7 @@ func TestCreateUser(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
CheckCreatedStatus(t, resp)
|
||||
|
||||
_, resp = th.Client.Login(user.Email, user.Password)
|
||||
session, _ := th.App.GetSession(th.Client.AuthToken)
|
||||
expectedCsrf := "MMCSRF=" + session.GetCSRF()
|
||||
actualCsrf := ""
|
||||
|
||||
for _, cookie := range resp.Header["Set-Cookie"] {
|
||||
if strings.HasPrefix(cookie, "MMCSRF") {
|
||||
cookieParts := strings.Split(cookie, ";")
|
||||
actualCsrf = cookieParts[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if expectedCsrf != actualCsrf {
|
||||
t.Errorf("CSRF Mismatch - Expected %s, got %s", expectedCsrf, actualCsrf)
|
||||
}
|
||||
_, _ = th.Client.Login(user.Email, user.Password)
|
||||
|
||||
if ruser.Nickname != user.Nickname {
|
||||
t.Fatal("nickname didn't match")
|
||||
@@ -2721,33 +2707,74 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoginCookies(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
th.Client.Logout()
|
||||
t.Run("should return cookies with X-Requested-With header", func(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
testCases := []struct {
|
||||
Description string
|
||||
SiteURL string
|
||||
ExpectedSetCookieHeaderRegexp string
|
||||
}{
|
||||
{"no subpath", "http://localhost:8065", "^MMAUTHTOKEN=[a-z0-9]+; Path=/"},
|
||||
{"subpath", "http://localhost:8065/subpath", "^MMAUTHTOKEN=[a-z0-9]+; Path=/subpath"},
|
||||
}
|
||||
th.Client.HttpHeader[model.HEADER_REQUESTED_WITH] = model.HEADER_REQUESTED_WITH_XML
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Description, func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.SiteURL = tc.SiteURL
|
||||
user, resp := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
|
||||
sessionCookie := ""
|
||||
userCookie := ""
|
||||
csrfCookie := ""
|
||||
|
||||
for _, cookie := range resp.Header["Set-Cookie"] {
|
||||
if match := regexp.MustCompile("^" + model.SESSION_COOKIE_TOKEN + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
||||
sessionCookie = match[1]
|
||||
} else if match := regexp.MustCompile("^" + model.SESSION_COOKIE_USER + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
||||
userCookie = match[1]
|
||||
} else if match := regexp.MustCompile("^" + model.SESSION_COOKIE_CSRF + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
||||
csrfCookie = match[1]
|
||||
}
|
||||
}
|
||||
|
||||
session, _ := th.App.GetSession(th.Client.AuthToken)
|
||||
|
||||
assert.Equal(t, th.Client.AuthToken, sessionCookie)
|
||||
assert.Equal(t, user.Id, userCookie)
|
||||
assert.Equal(t, session.GetCSRF(), csrfCookie)
|
||||
})
|
||||
|
||||
t.Run("should not return cookies without X-Requested-With header", func(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
_, resp := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
|
||||
assert.Empty(t, resp.Header.Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
t.Run("should include subpath in path", func(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.Client.HttpHeader[model.HEADER_REQUESTED_WITH] = model.HEADER_REQUESTED_WITH_XML
|
||||
|
||||
testCases := []struct {
|
||||
Description string
|
||||
SiteURL string
|
||||
ExpectedSetCookieHeaderRegexp string
|
||||
}{
|
||||
{"no subpath", "http://localhost:8065", "^MMAUTHTOKEN=[a-z0-9]+; Path=/"},
|
||||
{"subpath", "http://localhost:8065/subpath", "^MMAUTHTOKEN=[a-z0-9]+; Path=/subpath"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Description, func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.SiteURL = tc.SiteURL
|
||||
})
|
||||
|
||||
user, resp := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
CheckNoError(t, resp)
|
||||
assert.Equal(t, user.Id, th.BasicUser.Id)
|
||||
|
||||
cookies := resp.Header.Get("Set-Cookie")
|
||||
assert.Regexp(t, tc.ExpectedSetCookieHeaderRegexp, cookies)
|
||||
})
|
||||
|
||||
user, resp := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
CheckNoError(t, resp)
|
||||
assert.Equal(t, user.Id, th.BasicUser.Id)
|
||||
|
||||
cookies := resp.Header.Get("Set-Cookie")
|
||||
assert.Regexp(t, tc.ExpectedSetCookieHeaderRegexp, cookies)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCBALogin(t *testing.T) {
|
||||
|
||||
Ссылка в новой задаче
Block a user