From bbfdd4216fec7b70e01432244d71b7f49a5c0a56 Mon Sep 17 00:00:00 2001 From: James Hillyerd Date: Sat, 27 Feb 2016 15:43:44 -0800 Subject: [PATCH] Session cookie key is now configurable - Added [web] cookie.auth.key to configuration - Inbucket generates a random key if none is configured - Added [default] default.domain to be reference by SMTP and POP3 configs - Updated default/sample config files --- config/config.go | 10 ++++++++++ etc/devel.conf | 14 ++++++++++---- etc/docker/defaults/inbucket.conf | 15 ++++++++++----- etc/inbucket.conf | 14 ++++++++++---- etc/unix-sample.conf | 14 ++++++++++---- etc/win-sample.conf | 14 ++++++++++---- httpd/context.go | 13 ++++++++++--- httpd/server.go | 9 ++++++++- 8 files changed, 78 insertions(+), 25 deletions(-) diff --git a/config/config.go b/config/config.go index 9cb4f4a..2c648ec 100644 --- a/config/config.go +++ b/config/config.go @@ -39,6 +39,7 @@ type WebConfig struct { TemplateCache bool PublicDir string GreetingFile string + CookieAuthKey string } // DataStoreConfig contains the mail store configuration @@ -348,6 +349,15 @@ func parseWebConfig() error { } webConfig.GreetingFile = str + option = "cookie.auth.key" + if Config.HasOption(section, option) { + str, err = Config.String(section, option) + if err != nil { + return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err) + } + webConfig.CookieAuthKey = str + } + return nil } diff --git a/etc/devel.conf b/etc/devel.conf index dcc106a..2549705 100644 --- a/etc/devel.conf +++ b/etc/devel.conf @@ -6,6 +6,7 @@ # Not used directly, but is typically referenced below in %()s format. install.dir=. +default.domain=inbucket.local ############################################################################# [logging] @@ -23,7 +24,7 @@ ip4.address=0.0.0.0 ip4.port=2500 # used in SMTP greeting -domain=inbucket.local +domain=%(default.domain)s # optional: mail sent to accounts at this domain will not be stored, # for mixed use (content and load testing) @@ -54,7 +55,7 @@ ip4.address=0.0.0.0 ip4.port=1100 # used in POP3 greeting -domain=inbucket.local +domain=%(default.domain)s # How long we allow a network connection to be idle before hanging up on the # client, POP3 RFC requires at least 10 minutes (600 seconds). @@ -81,10 +82,15 @@ template.cache=false # Path to the selected themes public (static) files public.dir=%(install.dir)s/themes/%(theme)s/public -# Path to the greeting HTML displayed on front page, can -# be moved out of installation dir for customization +# Path to the greeting HTML displayed on front page, can be moved out of +# installation dir for customization greeting.file=%(install.dir)s/themes/greeting.html +# Key used to sign session cookie data so that it cannot be tampered with. +# If this is left unset, Inbucket will generate a random key at startup +# and previous sessions will be invalidated. +cookie.auth.key=secret-inbucket-session-cookie-key + ############################################################################# [datastore] diff --git a/etc/docker/defaults/inbucket.conf b/etc/docker/defaults/inbucket.conf index 6b6cf6a..5fb6192 100644 --- a/etc/docker/defaults/inbucket.conf +++ b/etc/docker/defaults/inbucket.conf @@ -8,7 +8,7 @@ # Not used directly, but is typically referenced below in %()s format. install.dir=/opt/inbucket -domain=inbucket.local +default.domain=inbucket.local ############################################################################# [logging] @@ -26,7 +26,7 @@ ip4.address=0.0.0.0 ip4.port=10025 # used in SMTP greeting -domain=inbucket.local +domain=%(default.domain)s # optional: mail sent to accounts at this domain will not be stored, # for mixed use (content and load testing) @@ -57,7 +57,7 @@ ip4.address=0.0.0.0 ip4.port=10110 # used in POP3 greeting -domain=%(domain) +domain=%(default.domain)s # How long we allow a network connection to be idle before hanging up on the # client, POP3 RFC requires at least 10 minutes (600 seconds). @@ -84,10 +84,15 @@ template.cache=true # Path to the selected themes public (static) files public.dir=%(install.dir)s/themes/%(theme)s/public -# Path to the greeting HTML displayed on front page, can -# be moved out of installation dir for customization +# Path to the greeting HTML displayed on front page, can be moved out of +# installation dir for customization greeting.file=/con/configuration/greeting.html +# Key used to sign session cookie data so that it cannot be tampered with. +# If this is left unset, Inbucket will generate a random key at startup +# and previous sessions will be invalidated. +#cookie.auth.key=secret-inbucket-session-cookie-key + ############################################################################# [datastore] diff --git a/etc/inbucket.conf b/etc/inbucket.conf index eebb0e6..e086f87 100644 --- a/etc/inbucket.conf +++ b/etc/inbucket.conf @@ -6,6 +6,7 @@ # Not used directly, but is typically referenced below in %()s format. install.dir=. +default.domain=inbucket.local ############################################################################# [logging] @@ -23,7 +24,7 @@ ip4.address=0.0.0.0 ip4.port=2500 # used in SMTP greeting -domain=inbucket.local +domain=%(default.domain)s # optional: mail sent to accounts at this domain will not be stored, # for mixed use (content and load testing) @@ -54,7 +55,7 @@ ip4.address=0.0.0.0 ip4.port=1100 # used in POP3 greeting -domain=inbucket.local +domain=%(default.domain)s # How long we allow a network connection to be idle before hanging up on the # client, POP3 RFC requires at least 10 minutes (600 seconds). @@ -81,10 +82,15 @@ template.cache=true # Path to the selected themes public (static) files public.dir=%(install.dir)s/themes/%(theme)s/public -# Path to the greeting HTML displayed on front page, can -# be moved out of installation dir for customization +# Path to the greeting HTML displayed on front page, can be moved out of +# installation dir for customization greeting.file=%(install.dir)s/themes/greeting.html +# Key used to sign session cookie data so that it cannot be tampered with. +# If this is left unset, Inbucket will generate a random key at startup +# and previous sessions will be invalidated. +#cookie.auth.key=secret-inbucket-session-cookie-key + ############################################################################# [datastore] diff --git a/etc/unix-sample.conf b/etc/unix-sample.conf index ebe03b9..07b8144 100644 --- a/etc/unix-sample.conf +++ b/etc/unix-sample.conf @@ -6,6 +6,7 @@ # Not used directly, but is typically referenced below in %()s format. install.dir=/opt/inbucket +default.domain=inbucket.local ############################################################################# [logging] @@ -23,7 +24,7 @@ ip4.address=0.0.0.0 ip4.port=25 # used in SMTP greeting -domain=inbucket.local +domain=%(default.domain)s # optional: mail sent to accounts at this domain will not be stored, # for mixed use (content and load testing) @@ -54,7 +55,7 @@ ip4.address=0.0.0.0 ip4.port=110 # used in POP3 greeting -domain=inbucket.local +domain=%(default.domain)s # How long we allow a network connection to be idle before hanging up on the # client, POP3 RFC requires at least 10 minutes (600 seconds). @@ -81,10 +82,15 @@ template.cache=true # Path to the selected themes public (static) files public.dir=%(install.dir)s/themes/%(theme)s/public -# Path to the greeting HTML displayed on front page, can -# be moved out of installation dir for customization +# Path to the greeting HTML displayed on front page, can be moved out of +# installation dir for customization greeting.file=%(install.dir)s/themes/greeting.html +# Key used to sign session cookie data so that it cannot be tampered with. +# If this is left unset, Inbucket will generate a random key at startup +# and previous sessions will be invalidated. +#cookie.auth.key=secret-inbucket-session-cookie-key + ############################################################################# [datastore] diff --git a/etc/win-sample.conf b/etc/win-sample.conf index 34b426f..fbbfbe2 100644 --- a/etc/win-sample.conf +++ b/etc/win-sample.conf @@ -6,6 +6,7 @@ # Not used directly, but is typically referenced below in %()s format. install.dir=. +default.domain=inbucket.local ############################################################################# [logging] @@ -23,7 +24,7 @@ ip4.address=0.0.0.0 ip4.port=2500 # used in SMTP greeting -domain=inbucket.local +domain=%(default.domain)s # optional: mail sent to accounts at this domain will not be stored, # for mixed use (content and load testing) @@ -54,7 +55,7 @@ ip4.address=0.0.0.0 ip4.port=1100 # used in POP3 greeting -domain=inbucket.local +domain=%(default.domain)s # How long we allow a network connection to be idle before hanging up on the # client, POP3 RFC requires at least 10 minutes (600 seconds). @@ -81,10 +82,15 @@ template.cache=true # Path to the selected themes public (static) files public.dir=%(install.dir)s\themes\%(theme)s\public -# Path to the greeting HTML displayed on front page, can -# be moved out of installation dir for customization +# Path to the greeting HTML displayed on front page, can be moved out of +# installation dir for customization greeting.file=%(install.dir)s\themes\greeting.html +# Key used to sign session cookie data so that it cannot be tampered with. +# If this is left unset, Inbucket will generate a random key at startup +# and previous sessions will be invalidated. +#cookie.auth.key=secret-inbucket-session-cookie-key + ############################################################################# [datastore] diff --git a/httpd/context.go b/httpd/context.go index e6fdc39..4087e57 100644 --- a/httpd/context.go +++ b/httpd/context.go @@ -43,14 +43,21 @@ func headerMatch(req *http.Request, name string, value string) bool { func NewContext(req *http.Request) (*Context, error) { vars := mux.Vars(req) sess, err := sessionStore.Get(req, "inbucket") + if err != nil { + if sess == nil { + // No session, must fail + return nil, err + } else { + // The session cookie was probably signed by an old key, ignore it + // gorilla created an empty session for us + err = nil + } + } ctx := &Context{ Vars: vars, Session: sess, DataStore: DataStore, IsJSON: headerMatch(req, "Accept", "application/json"), } - if err != nil { - return ctx, err - } return ctx, err } diff --git a/httpd/server.go b/httpd/server.go index 7959741..e0e6651 100644 --- a/httpd/server.go +++ b/httpd/server.go @@ -9,6 +9,7 @@ import ( "github.com/goods/httpbuf" "github.com/gorilla/mux" + "github.com/gorilla/securecookie" "github.com/gorilla/sessions" "github.com/jhillyerd/inbucket/config" "github.com/jhillyerd/inbucket/log" @@ -41,7 +42,13 @@ func Initialize(cfg config.WebConfig, ds smtpd.DataStore) { DataStore = ds // TODO Make configurable - sessionStore = sessions.NewCookieStore([]byte("something-very-secret")) + if cfg.CookieAuthKey == "" { + log.Infof("HTTP generating random cookie.auth.key") + sessionStore = sessions.NewCookieStore(securecookie.GenerateRandomKey(64)) + } else { + log.Tracef("HTTP using configured cookie.auth.key") + sessionStore = sessions.NewCookieStore([]byte(cfg.CookieAuthKey)) + } } func setupRoutes(cfg config.WebConfig) {