From 56ae1bd31c51387aefc6d5895fd6c73421c6a251 Mon Sep 17 00:00:00 2001 From: Cory Jacobsen Date: Sat, 2 Jul 2022 14:37:16 +0000 Subject: [PATCH] update docs, test regex --- README.md | 4 ++-- secure.go | 24 +++++++++++++++--------- secure_test.go | 28 +++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 056d73d..7eac2e9 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Secure comes with a variety of configuration options (Note: these are not the de // ... s := secure.New(secure.Options{ AllowedHosts: []string{"ssl.example.com"}, // AllowedHosts is a list of fully qualified domain names that are allowed. Default is empty list, which allows any and all host names. - AllowedHostsFunc: func() []string { return []string{"example\\.com", ".*\\.example\\.com" } // AllowedHostsFunc is a custom function that returns a list of fully qualified domain names that are allowed. This can be used in combination with the above AllowedHosts. - AllowedHostsAreRegex: false, // AllowedHostsAreRegex determines, if the provided AllowedHosts slice contains valid regular expressions. Default is false. + AllowedHostsFunc: func() []string { return []string{"example.com", "www.example.com" } // AllowedHostsFunc is a custom function that returns a list of fully qualified domain names that are allowed. This can be used in combination with the above AllowedHosts. + AllowedHostsAreRegex: false, // AllowedHostsAreRegex determines, if the provided AllowedHosts slice contains valid regular expressions. This does not apply to the `AllowedHostsFunc` values! Default is false. HostsProxyHeaders: []string{"X-Forwarded-Hosts"}, // HostsProxyHeaders is a set of header keys that may hold a proxied hostname value for the request. SSLRedirect: true, // If SSLRedirect is set to true, then only allow HTTPS requests. Default is false. SSLTemporaryRedirect: false, // If SSLTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301). diff --git a/secure.go b/secure.go index 754e1cc..a471150 100644 --- a/secure.go +++ b/secure.go @@ -33,10 +33,10 @@ const ( cspNonceSize = 16 ) -// SSLHostFunc a type whose pointer is the type of field `SSLHostFunc` of `Options` struct +// SSLHostFunc is a custom function type that can be used to dynamically set the SSL host of a request. type SSLHostFunc func(host string) (newHost string) -// AllowedHostsFunc a custom function type that returns a list of strings used in place of AllowedHosts list +// AllowedHostsFunc is a custom function type that can be used to dynamically return a slice of strings that will be used in the `AllowHosts` check. type AllowedHostsFunc func() []string func defaultBadHostHandler(w http.ResponseWriter, r *http.Request) { @@ -93,12 +93,11 @@ type Options struct { CrossOriginOpenerPolicy string // SSLHost is the host name that is used to redirect http requests to https. Default is "", which indicates to use the same host. SSLHost string - // AllowedHostsFunc is a custom function that returns a list of fully qualified domain names that are allowed. If set, values will be appended to AllowedHosts - AllowedHostsFunc AllowedHostsFunc - // AllowedHosts is a list of fully qualified domain names that are allowed. Default is empty list, which allows any and all host names. + // AllowedHosts is a slice of fully qualified domain names that are allowed. Default is an empty slice, which allows any and all host names. AllowedHosts []string - // AllowedHostsAreRegex determines, if the provided slice contains valid regular expressions. If this flag is set to true, every request's - // host will be checked against these expressions. Default is false for backwards compatibility. + // AllowedHostsFunc is a custom function that returns a slice of fully qualified domain names that are allowed. If set, values will be used in combination with the above AllowedHosts. Default is nil. + AllowedHostsFunc AllowedHostsFunc + // AllowedHostsAreRegex determines, if the provided `AllowedHosts` slice contains valid regular expressions. This does not apply to `AllowedHostsFunc`! If this flag is set to true, every request's host will be checked against these expressions. Default is false. AllowedHostsAreRegex bool // HostsProxyHeaders is a set of header keys that may hold a proxied hostname value for the request. HostsProxyHeaders []string @@ -296,9 +295,10 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He // Allowed hosts check. combinedAllowedHosts := s.opt.AllowedHosts - + var allowedFuncHosts []string if s.opt.AllowedHostsFunc != nil { - combinedAllowedHosts = append(combinedAllowedHosts, s.opt.AllowedHostsFunc()...) + allowedFuncHosts = s.opt.AllowedHostsFunc() + combinedAllowedHosts = append(combinedAllowedHosts, allowedFuncHosts...) } if len(combinedAllowedHosts) > 0 && !s.opt.IsDevelopment { @@ -310,6 +310,12 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He break } } + for _, allowedHost := range allowedFuncHosts { + if strings.EqualFold(allowedHost, host) { + isGoodHost = true + break + } + } } else { for _, allowedHost := range combinedAllowedHosts { if strings.EqualFold(allowedHost, host) { diff --git a/secure_test.go b/secure_test.go index d54db03..c99225b 100644 --- a/secure_test.go +++ b/secure_test.go @@ -1450,12 +1450,12 @@ func TestMultipleCustomSecureContextKeys(t *testing.T) { func TestAllowHostsFunc(t *testing.T) { s := New(Options{ - AllowedHostsFunc: func() []string { return []string{"www.example.com"} }, + AllowedHostsFunc: func() []string { return []string{"www.allow-func.com"} }, }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foo", nil) - req.Host = "www.example.com" + req.Host = "www.allow-func.com" s.Handler(myHandler).ServeHTTP(res, req) @@ -1466,7 +1466,7 @@ func TestAllowHostsFunc(t *testing.T) { func TestAllowHostsFuncWithAllowedHostsList(t *testing.T) { s := New(Options{ AllowedHosts: []string{"www.allow.com"}, - AllowedHostsFunc: func() []string { return []string{"www.allowfunc.com"} }, + AllowedHostsFunc: func() []string { return []string{"www.allow-func.com"} }, }) res := httptest.NewRecorder() @@ -1479,6 +1479,28 @@ func TestAllowHostsFuncWithAllowedHostsList(t *testing.T) { expect(t, res.Body.String(), `bar`) } +func TestAllowHostsFuncWithAllowedHostsListWithRegex(t *testing.T) { + s := New(Options{ + AllowedHosts: []string{"*\\.allow\\.com"}, + AllowedHostsFunc: func() []string { return []string{"foo.bar.allow.com"} }, + AllowedHostsAreRegex: true, + }) + + res := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/foo", nil) + req.Host = "foo.bar.allow.com" + s.Handler(myHandler).ServeHTTP(res, req) + expect(t, res.Code, http.StatusOK) + expect(t, res.Body.String(), `bar`) + + res = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "/foo", nil) + req.Host = "bar.allow.com" + s.Handler(myHandler).ServeHTTP(res, req) + expect(t, res.Code, http.StatusOK) + expect(t, res.Body.String(), `bar`) +} + /* Test Helpers */ func expect(t *testing.T, a interface{}, b interface{}) { if a != b {