Add a configurable URL redirect parameter for error URLs

This commit is contained in:
Ian Buss 2020-08-18 10:03:38 +01:00
parent 3d1acf6db0
commit 41cf628bdf
11 changed files with 233 additions and 86 deletions

View file

@ -37,31 +37,32 @@ import (
)
const (
customHTTPErrors = "custom-http-errors"
skipAccessLogUrls = "skip-access-log-urls"
whitelistSourceRange = "whitelist-source-range"
proxyRealIPCIDR = "proxy-real-ip-cidr"
bindAddress = "bind-address"
httpRedirectCode = "http-redirect-code"
blockCIDRs = "block-cidrs"
blockUserAgents = "block-user-agents"
blockReferers = "block-referers"
proxyStreamResponses = "proxy-stream-responses"
hideHeaders = "hide-headers"
nginxStatusIpv4Whitelist = "nginx-status-ipv4-whitelist"
nginxStatusIpv6Whitelist = "nginx-status-ipv6-whitelist"
proxyHeaderTimeout = "proxy-protocol-header-timeout"
workerProcesses = "worker-processes"
globalAuthURL = "global-auth-url"
globalAuthMethod = "global-auth-method"
globalAuthSignin = "global-auth-signin"
globalAuthResponseHeaders = "global-auth-response-headers"
globalAuthRequestRedirect = "global-auth-request-redirect"
globalAuthSnippet = "global-auth-snippet"
globalAuthCacheKey = "global-auth-cache-key"
globalAuthCacheDuration = "global-auth-cache-duration"
luaSharedDictsKey = "lua-shared-dicts"
plugins = "plugins"
customHTTPErrors = "custom-http-errors"
skipAccessLogUrls = "skip-access-log-urls"
whitelistSourceRange = "whitelist-source-range"
proxyRealIPCIDR = "proxy-real-ip-cidr"
bindAddress = "bind-address"
httpRedirectCode = "http-redirect-code"
blockCIDRs = "block-cidrs"
blockUserAgents = "block-user-agents"
blockReferers = "block-referers"
proxyStreamResponses = "proxy-stream-responses"
hideHeaders = "hide-headers"
nginxStatusIpv4Whitelist = "nginx-status-ipv4-whitelist"
nginxStatusIpv6Whitelist = "nginx-status-ipv6-whitelist"
proxyHeaderTimeout = "proxy-protocol-header-timeout"
workerProcesses = "worker-processes"
globalAuthURL = "global-auth-url"
globalAuthMethod = "global-auth-method"
globalAuthSignin = "global-auth-signin"
globalAuthSigninRedirectParam = "global-auth-signin-redirect-param"
globalAuthResponseHeaders = "global-auth-response-headers"
globalAuthRequestRedirect = "global-auth-request-redirect"
globalAuthSnippet = "global-auth-snippet"
globalAuthCacheKey = "global-auth-cache-key"
globalAuthCacheDuration = "global-auth-cache-duration"
luaSharedDictsKey = "lua-shared-dicts"
plugins = "plugins"
)
var (
@ -75,6 +76,7 @@ var (
"certificate_servers": 5,
"ocsp_response_cache": 5, // keep this same as certificate_servers
}
defaultGlobalAuthRedirectParam = "rd"
)
const (
@ -254,6 +256,19 @@ func ReadConfig(src map[string]string) config.Configuration {
}
}
// Verify that the configured global external authorization error page redirection URL parameter is set and valid. if not, set the default value
if val, ok := conf[globalAuthSigninRedirectParam]; ok {
delete(conf, globalAuthSigninRedirectParam)
redirectParam := strings.TrimSpace(val)
dummySigninURL, _ := parser.StringToURL(fmt.Sprintf("%s?%s=dummy", to.GlobalExternalAuth.SigninURL, redirectParam))
if dummySigninURL == nil {
klog.Warningf("Global auth redirect parameter denied - %v.", "global-auth-signin-redirect-param setting is invalid and will not be set")
} else {
to.GlobalExternalAuth.SigninURLRedirectParam = redirectParam
}
}
// Verify that the configured global external authorization response headers are valid. if not, set the default value
if val, ok := conf[globalAuthResponseHeaders]; ok {
delete(conf, globalAuthResponseHeaders)

View file

@ -229,6 +229,28 @@ func TestGlobalExternalAuthSigninParsing(t *testing.T) {
}
}
func TestGlobalExternalAuthSigninRedirectParamParsing(t *testing.T) {
testCases := map[string]struct {
param string
signin string
expect string
}{
"no param": {"", "http://bar.foo.com/auth-error-page", ""},
"valid param": {"orig", "http://bar.foo.com/auth-error-page", "orig"},
"no signin url": {"orig", "", ""},
}
for n, tc := range testCases {
cfg := ReadConfig(map[string]string{
"global-auth-signin": tc.signin,
"global-auth-signin-redirect-param": tc.param,
})
if cfg.GlobalExternalAuth.SigninURLRedirectParam != tc.expect {
t.Errorf("Testing %v. Expected \"%v\" but \"%v\" was returned", n, tc.expect, cfg.GlobalExternalAuth.SigninURLRedirectParam)
}
}
}
func TestGlobalExternalAuthResponseHeadersParsing(t *testing.T) {
testCases := map[string]struct {
headers string

View file

@ -50,9 +50,10 @@ import (
)
const (
slash = "/"
nonIdempotent = "non_idempotent"
defBufferSize = 65535
slash = "/"
nonIdempotent = "non_idempotent"
defBufferSize = 65535
defAuthSigninRedirectParam = "rd"
)
// TemplateWriter is the interface to render a template
@ -903,18 +904,21 @@ func buildForwardedFor(input interface{}) string {
return fmt.Sprintf("$http_%v", ffh)
}
func buildAuthSignURL(authSignURL string) string {
func buildAuthSignURL(authSignURL, authRedirectParam string) string {
u, _ := url.Parse(authSignURL)
q := u.Query()
if authRedirectParam == "" {
authRedirectParam = defaultGlobalAuthRedirectParam
}
if len(q) == 0 {
return fmt.Sprintf("%v?rd=$pass_access_scheme://$http_host$escaped_request_uri", authSignURL)
return fmt.Sprintf("%v?%v=$pass_access_scheme://$http_host$escaped_request_uri", authSignURL, authRedirectParam)
}
if q.Get("rd") != "" {
if q.Get(authRedirectParam) != "" {
return authSignURL
}
return fmt.Sprintf("%v&rd=$pass_access_scheme://$http_host$escaped_request_uri", authSignURL)
return fmt.Sprintf("%v&%v=$pass_access_scheme://$http_host$escaped_request_uri", authSignURL, authRedirectParam)
}
func buildAuthSignURLLocation(location, authSignURL string) string {

View file

@ -766,16 +766,19 @@ func TestFilterRateLimits(t *testing.T) {
func TestBuildAuthSignURL(t *testing.T) {
cases := map[string]struct {
Input, Output string
Input, RedirectParam, Output string
}{
"default url": {"http://google.com", "http://google.com?rd=$pass_access_scheme://$http_host$escaped_request_uri"},
"with random field": {"http://google.com?cat=0", "http://google.com?cat=0&rd=$pass_access_scheme://$http_host$escaped_request_uri"},
"with rd field": {"http://google.com?cat&rd=$request", "http://google.com?cat&rd=$request"},
"default url and redirect": {"http://google.com", "rd", "http://google.com?rd=$pass_access_scheme://$http_host$escaped_request_uri"},
"default url and custom redirect": {"http://google.com", "orig", "http://google.com?orig=$pass_access_scheme://$http_host$escaped_request_uri"},
"with random field": {"http://google.com?cat=0", "rd", "http://google.com?cat=0&rd=$pass_access_scheme://$http_host$escaped_request_uri"},
"with random field and custom redirect": {"http://google.com?cat=0", "orig", "http://google.com?cat=0&orig=$pass_access_scheme://$http_host$escaped_request_uri"},
"with rd field": {"http://google.com?cat&rd=$request", "rd", "http://google.com?cat&rd=$request"},
"with orig field": {"http://google.com?cat&orig=$request", "orig", "http://google.com?cat&orig=$request"},
}
for k, tc := range cases {
res := buildAuthSignURL(tc.Input)
res := buildAuthSignURL(tc.Input, tc.RedirectParam)
if res != tc.Output {
t.Errorf("%s: called buildAuthSignURL('%s'); expected '%v' but returned '%v'", k, tc.Input, tc.Output, res)
t.Errorf("%s: called buildAuthSignURL('%s','%s'); expected '%v' but returned '%v'", k, tc.Input, tc.RedirectParam, tc.Output, res)
}
}
}