From 2102f9d92db308f694707ebe6253beb20c5f7505 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Fri, 12 Jul 2019 06:57:31 -0700 Subject: [PATCH] Support setting cookie domain (#6288) Signed-off-by: Tamal Saha --- custom/conf/app.ini.sample | 2 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + go.mod | 4 ++-- go.sum | 8 +++---- modules/setting/session.go | 1 + modules/setting/setting.go | 5 +++- routers/routes/routes.go | 16 +++++++------ routers/user/auth.go | 24 +++++++++---------- routers/user/setting/profile.go | 2 +- vendor/github.com/go-macaron/csrf/.travis.yml | 1 - vendor/github.com/go-macaron/csrf/csrf.go | 11 ++++++--- vendor/github.com/go-macaron/csrf/xsrf.go | 4 ++-- vendor/github.com/go-macaron/i18n/.travis.yml | 15 +++++------- vendor/github.com/go-macaron/i18n/i18n.go | 6 +++-- vendor/modules.txt | 4 ++-- 15 files changed, 58 insertions(+), 46 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e44cc90a4b..0212964750 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -321,6 +321,8 @@ IMPORT_LOCAL_PATHS = false DISABLE_GIT_HOOKS = false ; Password Hash algorithm, either "pbkdf2", "argon2", "scrypt" or "bcrypt" PASSWORD_HASH_ALGO = pbkdf2 +; Set false to allow JavaScript to read CSRF cookie +CSRF_COOKIE_HTTP_ONLY = true [openid] ; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 61905f8ad8..6f3bc465a6 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -198,6 +198,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `INTERNAL_TOKEN`: **\**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) - `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[pbkdf2, argon2, scrypt, bcrypt\]. +- `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie. ## OpenID (`openid`) diff --git a/go.mod b/go.mod index 8fdf57b3fc..182f8aca98 100644 --- a/go.mod +++ b/go.mod @@ -47,8 +47,8 @@ require ( github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 - github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 - github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f + github.com/go-macaron/csrf v0.0.0-20190131233648-3751b136073c + github.com/go-macaron/i18n v0.0.0-20190131234336-56731837a73b github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90 diff --git a/go.sum b/go.sum index 8a617be49c..5256f0ce80 100644 --- a/go.sum +++ b/go.sum @@ -117,10 +117,10 @@ github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/D github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E= -github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= -github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= -github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f h1:wDKrZFc9pYJlqFOf7EzGbFMrSFFtyHt3plr2uTdo8Rg= -github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f/go.mod h1:MePM/dStkAh+PNzAdNSNl4SGDM2EZvZGken+KpJhM7s= +github.com/go-macaron/csrf v0.0.0-20190131233648-3751b136073c h1:yCyrJuFaxKX/VoV9hHqYXhkFEMtg+Hxsiitk1z/lHfQ= +github.com/go-macaron/csrf v0.0.0-20190131233648-3751b136073c/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= +github.com/go-macaron/i18n v0.0.0-20190131234336-56731837a73b h1:p19t0uFyv0zkBwp4dafzU3EcpHilHNffTVDmxpn/M+w= +github.com/go-macaron/i18n v0.0.0-20190131234336-56731837a73b/go.mod h1:MePM/dStkAh+PNzAdNSNl4SGDM2EZvZGken+KpJhM7s= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 h1:z/nqwd+ql/r6Q3QGnwNd6B89UjPytM0be5pDQV9TuWw= diff --git a/modules/setting/session.go b/modules/setting/session.go index 313c3c76b5..7009576ccb 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -34,6 +34,7 @@ func newSessionService() { SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool(false) SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(86400) SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400) + SessionConfig.Domain = Cfg.Section("session").Key("DOMAIN").String() shadowConfig, err := json.Marshal(SessionConfig) if err != nil { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7201f0619d..6a5c5a36d7 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -287,7 +287,8 @@ var ( // Time settings TimeFormat string - CSRFCookieName = "_csrf" + CSRFCookieName = "_csrf" + CSRFCookieHTTPOnly = true // Mirror settings Mirror struct { @@ -781,6 +782,8 @@ func NewContext() { ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false) PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") + CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) + InternalToken = loadInternalToken(sec) IterateBufferSize = Cfg.Section("database").Key("ITERATE_BUFFER_SIZE").MustInt(50) LogSQL = Cfg.Section("database").Key("LOG_SQL").MustBool(true) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index ec57e8f5fd..c81d56064c 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -181,12 +181,13 @@ func NewMacaron() *macaron.Macaron { } m.Use(i18n.I18n(i18n.Options{ - SubURL: setting.AppSubURL, - Files: localFiles, - Langs: setting.Langs, - Names: setting.Names, - DefaultLang: "en-US", - Redirect: false, + SubURL: setting.AppSubURL, + Files: localFiles, + Langs: setting.Langs, + Names: setting.Names, + DefaultLang: "en-US", + Redirect: false, + CookieDomain: setting.SessionConfig.Domain, })) m.Use(cache.Cacher(cache.Options{ Adapter: setting.CacheService.Adapter, @@ -202,8 +203,9 @@ func NewMacaron() *macaron.Macaron { Cookie: setting.CSRFCookieName, SetCookie: true, Secure: setting.SessionConfig.Secure, - CookieHttpOnly: true, + CookieHttpOnly: setting.CSRFCookieHTTPOnly, Header: "X-Csrf-Token", + CookieDomain: setting.SessionConfig.Domain, CookiePath: setting.AppSubURL, })) m.Use(toolbox.Toolboxer(m, toolbox.Options{ diff --git a/routers/user/auth.go b/routers/user/auth.go index 8203593739..f78171a1b7 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -58,8 +58,8 @@ func AutoSignIn(ctx *context.Context) (bool, error) { defer func() { if !isSucceed { log.Trace("auto-login cookie cleared: %s", uname) - ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) - ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) } }() @@ -85,7 +85,7 @@ func AutoSignIn(ctx *context.Context) (bool, error) { if err != nil { return false, err } - ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) return true, nil } @@ -475,9 +475,9 @@ func handleSignIn(ctx *context.Context, u *models.User, remember bool) { func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyRedirect bool) string { if remember { days := 86400 * setting.LogInRememberDays - ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd), - setting.CookieRememberName, u.Name, days, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + setting.CookieRememberName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) } _ = ctx.Session.Delete("openid_verified_uri") @@ -507,10 +507,10 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR } } - ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Clear whatever CSRF has right now, force to generate a new one - ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Register last login u.SetLastLogin() @@ -610,7 +610,7 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context } // Clear whatever CSRF has right now, force to generate a new one - ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Register last login u.SetLastLogin() @@ -968,10 +968,10 @@ func handleSignOut(ctx *context.Context) { _ = ctx.Session.Delete("socialId") _ = ctx.Session.Delete("socialName") _ = ctx.Session.Delete("socialEmail") - ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) - ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) - ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) - ctx.SetCookie("lang", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state. + ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + ctx.SetCookie("lang", "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state. } // SignOut sign out from login status diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index 163bc869b4..64828e90ee 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -104,7 +104,7 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { } // Update the language to the one we just set - ctx.SetCookie("lang", ctx.User.Language, nil, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.SetCookie("lang", ctx.User.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) log.Trace("User settings updated: %s", ctx.User.Name) ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_profile_success")) diff --git a/vendor/github.com/go-macaron/csrf/.travis.yml b/vendor/github.com/go-macaron/csrf/.travis.yml index 8d6a90868c..81680f0f02 100644 --- a/vendor/github.com/go-macaron/csrf/.travis.yml +++ b/vendor/github.com/go-macaron/csrf/.travis.yml @@ -1,7 +1,6 @@ sudo: false language: go go: - - 1.5.x - 1.6.x - 1.7.x - 1.8.x diff --git a/vendor/github.com/go-macaron/csrf/csrf.go b/vendor/github.com/go-macaron/csrf/csrf.go index 19c9b479fa..00f3c3c9c0 100644 --- a/vendor/github.com/go-macaron/csrf/csrf.go +++ b/vendor/github.com/go-macaron/csrf/csrf.go @@ -25,7 +25,7 @@ import ( "gopkg.in/macaron.v1" ) -const _VERSION = "0.1.0" +const _VERSION = "0.1.1" func Version() string { return _VERSION @@ -58,6 +58,8 @@ type csrf struct { Form string // Cookie name value for setting and getting csrf token. Cookie string + //Cookie domain + CookieDomain string //Cookie path CookiePath string // Cookie HttpOnly flag value used for the csrf token. @@ -123,8 +125,10 @@ type Options struct { Form string // Cookie value used to set and get token. Cookie string + // Cookie domain. + CookieDomain string // Cookie path. - CookiePath string + CookiePath string CookieHttpOnly bool // Key used for getting the unique ID per user. SessionKey string @@ -187,6 +191,7 @@ func Generate(options ...Options) macaron.Handler { Header: opt.Header, Form: opt.Form, Cookie: opt.Cookie, + CookieDomain: opt.CookieDomain, CookiePath: opt.CookiePath, CookieHttpOnly: opt.CookieHttpOnly, ErrorFunc: opt.ErrorFunc, @@ -222,7 +227,7 @@ func Generate(options ...Options) macaron.Handler { // FIXME: actionId. x.Token = GenerateToken(x.Secret, x.ID, "POST") if opt.SetCookie { - ctx.SetCookie(opt.Cookie, x.Token, 0, opt.CookiePath, "", opt.Secure, opt.CookieHttpOnly, time.Now().AddDate(0, 0, 1)) + ctx.SetCookie(opt.Cookie, x.Token, 0, opt.CookiePath, opt.CookieDomain, opt.Secure, opt.CookieHttpOnly, time.Now().AddDate(0, 0, 1)) } } diff --git a/vendor/github.com/go-macaron/csrf/xsrf.go b/vendor/github.com/go-macaron/csrf/xsrf.go index 81ed5d0fc5..7f31894f95 100644 --- a/vendor/github.com/go-macaron/csrf/xsrf.go +++ b/vendor/github.com/go-macaron/csrf/xsrf.go @@ -50,7 +50,7 @@ func generateTokenAtTime(key, userID, actionID string, now time.Time) string { h := hmac.New(sha1.New, []byte(key)) fmt.Fprintf(h, "%s:%s:%d", clean(userID), clean(actionID), now.UnixNano()) tok := fmt.Sprintf("%s:%d", h.Sum(nil), now.UnixNano()) - return base64.URLEncoding.EncodeToString([]byte(tok)) + return base64.RawURLEncoding.EncodeToString([]byte(tok)) } // Valid returns true if token is a valid, unexpired token returned by Generate. @@ -61,7 +61,7 @@ func ValidToken(token, key, userID, actionID string) bool { // validTokenAtTime is like Valid, but it uses now to check if the token is expired. func validTokenAtTime(token, key, userID, actionID string, now time.Time) bool { // Decode the token. - data, err := base64.URLEncoding.DecodeString(token) + data, err := base64.RawURLEncoding.DecodeString(token) if err != nil { return false } diff --git a/vendor/github.com/go-macaron/i18n/.travis.yml b/vendor/github.com/go-macaron/i18n/.travis.yml index 2774fb35d5..f331c2c84a 100644 --- a/vendor/github.com/go-macaron/i18n/.travis.yml +++ b/vendor/github.com/go-macaron/i18n/.travis.yml @@ -1,14 +1,11 @@ sudo: false language: go - go: - - 1.3 - - 1.4 - - 1.5 - - tip + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x script: go test -v -cover -race - -notifications: - email: - - u@gogs.io diff --git a/vendor/github.com/go-macaron/i18n/i18n.go b/vendor/github.com/go-macaron/i18n/i18n.go index 3b5b1b834d..4f386a0bbd 100644 --- a/vendor/github.com/go-macaron/i18n/i18n.go +++ b/vendor/github.com/go-macaron/i18n/i18n.go @@ -26,7 +26,7 @@ import ( "gopkg.in/macaron.v1" ) -const _VERSION = "0.3.0" +const _VERSION = "0.4.0" func Version() string { return _VERSION @@ -96,6 +96,8 @@ type Options struct { TmplName string // Configuration section name. Default is "i18n". Section string + // Domain used for `lang` cookie. Default is "" + CookieDomain string } func prepareOptions(options []Options) Options { @@ -193,7 +195,7 @@ func I18n(options ...Options) macaron.Handler { // Save language information in cookies. if !hasCookie { - ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/"+strings.TrimPrefix(opt.SubURL, "/")) + ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/"+strings.TrimPrefix(opt.SubURL, "/"), opt.CookieDomain) } restLangs := make([]LangType, 0, i18n.Count()-1) diff --git a/vendor/modules.txt b/vendor/modules.txt index 0e9d3c3163..567ace1877 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -128,9 +128,9 @@ github.com/go-macaron/cache/redis github.com/go-macaron/captcha # github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/cors -# github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 +# github.com/go-macaron/csrf v0.0.0-20190131233648-3751b136073c github.com/go-macaron/csrf -# github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f +# github.com/go-macaron/i18n v0.0.0-20190131234336-56731837a73b github.com/go-macaron/i18n # github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 github.com/go-macaron/inject