[MM-39583] - Intermediary web login page: Workspace Cookies (#19256)
* [MM-39583] - Intermediary web login page: Workspace Cookies * only cloud * fix error with license check * feedback impl * improvement * make improvements Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
8ad9a22e77
Коммит
664af506a3
@@ -251,6 +251,26 @@ func Setup(tb testing.TB) *TestHelper {
|
|||||||
return th
|
return th
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetupAndApplyConfigBeforeLogin(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
||||||
|
if testing.Short() {
|
||||||
|
tb.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if mainHelper == nil {
|
||||||
|
tb.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
dbStore := mainHelper.GetStore()
|
||||||
|
dbStore.DropAllTables()
|
||||||
|
dbStore.MarkSystemRanUnitTests()
|
||||||
|
mainHelper.PreloadMigrations()
|
||||||
|
searchEngine := mainHelper.GetSearchEngine()
|
||||||
|
th := setupTestHelper(dbStore, searchEngine, false, true, nil, nil)
|
||||||
|
th.App.UpdateConfig(updateConfig)
|
||||||
|
th.InitLogin()
|
||||||
|
return th
|
||||||
|
}
|
||||||
|
|
||||||
func SetupConfig(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
func SetupConfig(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
tb.SkipNow()
|
tb.SkipNow()
|
||||||
|
|||||||
@@ -1852,6 +1852,11 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
c.App.AttachSessionCookies(c.AppContext, w, r)
|
c.App.AttachSessionCookies(c.AppContext, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For context see: https://mattermost.atlassian.net/browse/MM-39583
|
||||||
|
if c.App.Srv().License() != nil && *c.App.Srv().License().Features.Cloud {
|
||||||
|
c.App.AttachCloudSessionCookie(c.AppContext, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
|
userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
|
||||||
if err != nil && err.StatusCode != http.StatusNotFound {
|
if err != nil && err.StatusCode != http.StatusNotFound {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
|
|||||||
@@ -3640,6 +3640,46 @@ func TestLoginCookies(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should return cookie with MMCLOUDURL for cloud installations", func(t *testing.T) {
|
||||||
|
updateConfig := func(cfg *model.Config) {
|
||||||
|
*cfg.ServiceSettings.AllowCookiesForSubdomains = true
|
||||||
|
*cfg.ServiceSettings.SiteURL = "https://testchips.cloud.mattermost.com"
|
||||||
|
}
|
||||||
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
||||||
|
|
||||||
|
_, resp, _ := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||||
|
|
||||||
|
val := strings.Split(resp.Header["Set-Cookie"][0], ";")
|
||||||
|
cloudSessionCookie := strings.Split(val[0], "=")[1]
|
||||||
|
domain := strings.Split(val[2], "=")[1]
|
||||||
|
|
||||||
|
assert.Equal(t, "testchips", cloudSessionCookie)
|
||||||
|
assert.Equal(t, "mattermost.com", domain)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should NOT return cookie with MMCLOUDURL for NON cloud installations", func(t *testing.T) {
|
||||||
|
updateConfig := func(cfg *model.Config) {
|
||||||
|
*cfg.ServiceSettings.AllowCookiesForSubdomains = true
|
||||||
|
*cfg.ServiceSettings.SiteURL = "https://testchips.com"
|
||||||
|
}
|
||||||
|
th := SetupAndApplyConfigBeforeLogin(t, updateConfig).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
_, resp, _ := th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||||
|
|
||||||
|
cloudSessionCookie := ""
|
||||||
|
for _, cookie := range resp.Header["Set-Cookie"] {
|
||||||
|
if match := regexp.MustCompile("^" + model.SessionCookieCloudUrl + "=([a-z0-9]+)").FindStringSubmatch(cookie); match != nil {
|
||||||
|
cloudSessionCookie = match[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no cookie set
|
||||||
|
assert.Equal(t, "", cloudSessionCookie)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCBALogin(t *testing.T) {
|
func TestCBALogin(t *testing.T) {
|
||||||
|
|||||||
@@ -391,6 +391,7 @@ type AppIface interface {
|
|||||||
AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError)
|
AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError)
|
||||||
AppendFile(fr io.Reader, path string) (int64, *model.AppError)
|
AppendFile(fr io.Reader, path string) (int64, *model.AppError)
|
||||||
AsymmetricSigningKey() *ecdsa.PrivateKey
|
AsymmetricSigningKey() *ecdsa.PrivateKey
|
||||||
|
AttachCloudSessionCookie(c *request.Context, w http.ResponseWriter, r *http.Request)
|
||||||
AttachDeviceId(sessionID string, deviceID string, expiresAt int64) *model.AppError
|
AttachDeviceId(sessionID string, deviceID string, expiresAt int64) *model.AppError
|
||||||
AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request)
|
AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request)
|
||||||
AuthenticateUserForLogin(c *request.Context, id, loginId, password, mfaToken, cwsToken string, ldapOnly bool) (user *model.User, err *model.AppError)
|
AuthenticateUserForLogin(c *request.Context, id, loginId, password, mfaToken, cwsToken string, ldapOnly bool) (user *model.User, err *model.AppError)
|
||||||
|
|||||||
33
app/login.go
33
app/login.go
@@ -238,6 +238,39 @@ func (a *App) DoLogin(c *request.Context, w http.ResponseWriter, r *http.Request
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) AttachCloudSessionCookie(c *request.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
secure := false
|
||||||
|
if GetProtocol(r) == "https" {
|
||||||
|
secure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
maxAge := *a.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24
|
||||||
|
domain := a.GetCookieDomain()
|
||||||
|
subpath, _ := utils.GetSubpathFromConfig(a.Config())
|
||||||
|
expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0)
|
||||||
|
|
||||||
|
var val string
|
||||||
|
if strings.Contains(domain, "localhost") {
|
||||||
|
val = "localhost"
|
||||||
|
} else {
|
||||||
|
val = strings.SplitN(domain, ".", 2)[0]
|
||||||
|
domain = strings.SplitN(domain, ".", 3)[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie := &http.Cookie{
|
||||||
|
Name: model.SessionCookieCloudUrl,
|
||||||
|
Value: val,
|
||||||
|
Path: subpath,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
Expires: expiresAt,
|
||||||
|
HttpOnly: true,
|
||||||
|
Domain: domain,
|
||||||
|
Secure: secure,
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, cookie)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request) {
|
func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
secure := false
|
secure := false
|
||||||
if GetProtocol(r) == "https" {
|
if GetProtocol(r) == "https" {
|
||||||
|
|||||||
@@ -686,6 +686,21 @@ func (a *OpenTracingAppLayer) AsymmetricSigningKey() *ecdsa.PrivateKey {
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) AttachCloudSessionCookie(c *request.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AttachCloudSessionCookie")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
a.app.AttachCloudSessionCookie(c, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) AttachDeviceId(sessionID string, deviceID string, expiresAt int64) *model.AppError {
|
func (a *OpenTracingAppLayer) AttachDeviceId(sessionID string, deviceID string, expiresAt int64) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AttachDeviceId")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AttachDeviceId")
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const (
|
|||||||
SessionCookieToken = "MMAUTHTOKEN"
|
SessionCookieToken = "MMAUTHTOKEN"
|
||||||
SessionCookieUser = "MMUSERID"
|
SessionCookieUser = "MMUSERID"
|
||||||
SessionCookieCsrf = "MMCSRF"
|
SessionCookieCsrf = "MMCSRF"
|
||||||
|
SessionCookieCloudUrl = "MMCLOUDURL"
|
||||||
SessionCacheSize = 35000
|
SessionCacheSize = 35000
|
||||||
SessionPropPlatform = "platform"
|
SessionPropPlatform = "platform"
|
||||||
SessionPropOs = "os"
|
SessionPropOs = "os"
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user