Skip to content

Commit

Permalink
update docs, test regex
Browse files Browse the repository at this point in the history
  • Loading branch information
unrolled committed Jul 2, 2022
1 parent 764d6a2 commit 56ae1bd
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 14 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
24 changes: 15 additions & 9 deletions secure.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down
28 changes: 25 additions & 3 deletions secure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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()
Expand All @@ -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 {
Expand Down

0 comments on commit 56ae1bd

Please sign in to comment.