Support HTTP method based allowlists

This commit is contained in:
Nick Meves 2020-09-22 18:54:32 -07:00
parent fcb83c48f4
commit 183cb124a4
No known key found for this signature in database
GPG Key ID: 93BA8A3CEDCDD1CF
8 changed files with 309 additions and 125 deletions

View File

@ -7,6 +7,9 @@
- [#575](https://github.com/oauth2-proxy/oauth2-proxy/pull/575) Sessions from v5.1.1 or earlier will no longer validate since they were not signed with SHA1.
- Sessions from v6.0.0 or later had a graceful conversion to SHA256 that resulted in no reauthentication
- Upgrading from v5.1.1 or earlier will result in a reauthentication
- [#789](https://github.com/oauth2-proxy/oauth2-proxy/pull/789) `--skip-auth-route` is (almost) backwards compatible with `--skip-auth-regex`
- We are marking `--skip-auth-regex` as DEPRECATED and will remove it in the next major version.
- If your regex contains an `=` and you want it for all methods, you will need to add a leading `=` (this is the area where `--skip-auth-regex` doesn't port perfectly)
- [#616](https://github.com/oauth2-proxy/oauth2-proxy/pull/616) Ensure you have configured oauth2-proxy to use the `groups` scope. The user may be logged out initially as they may not currently have the `groups` claim however after going back through login process wil be authenticated.
## Breaking Changes
@ -23,6 +26,7 @@
## Changes since v6.1.1
- [#753](https://github.com/oauth2-proxy/oauth2-proxy/pull/753) Pass resource parameter in login url (@codablock)
- [#789](https://github.com/oauth2-proxy/oauth2-proxy/pull/789) Add `--skip-auth-route` configuration option for `METHOD=pathRegex` based allowlists (@NickMeves)
- [#575](https://github.com/oauth2-proxy/oauth2-proxy/pull/575) Stop accepting legacy SHA1 signed cookies (@NickMeves)
- [#722](https://github.com/oauth2-proxy/oauth2-proxy/pull/722) Validate Redis configuration options at startup (@NickMeves)
- [#791](https://github.com/oauth2-proxy/oauth2-proxy/pull/791) Remove GetPreferredUsername method from provider interface (@NickMeves)

View File

@ -119,8 +119,9 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example
| `--signature-key` | string | GAP-Signature request signature key (algorithm:secretkey) | |
| `--silence-ping-logging` | bool | disable logging of requests to ping endpoint | false |
| `--skip-auth-preflight` | bool | will skip authentication for OPTIONS requests | false |
| `--skip-auth-regex` | string | bypass authentication for requests paths that match (may be given multiple times) | |
| `--skip-auth-strip-headers` | bool | strips `X-Forwarded-*` style authentication headers & `Authorization` header if they would be set by oauth2-proxy for request paths in `--skip-auth-regex` | false |
| `--skip-auth-regex` | string \| list | (DEPRECATED for `--skip-auth-route`) bypass authentication for requests paths that match (may be given multiple times) | |
| `--skip-auth-route` | string \| list | bypass authentication for requests that match the method & path. Format: method=path_regex OR path_regex alone for all methods | |
| `--skip-auth-strip-headers` | bool | strips `X-Forwarded-*` style authentication headers & `Authorization` header if they would be set by oauth2-proxy for allowlisted requests (`--skip-auth-route`, `--skip-auth-regex`, `--skip-auth-preflight`, `--trusted-ip`) | false |
| `--skip-jwt-bearer-tokens` | bool | will skip requests that have verified JWT bearer tokens | false |
| `--skip-oidc-discovery` | bool | bypass OIDC endpoint discovery. `--login-url`, `--redeem-url` and `--oidc-jwks-url` must be configured in this case | false |
| `--skip-provider-button` | bool | will skip sign-in-page to directly reach the next step: oauth/start | false |

View File

@ -48,6 +48,12 @@ var (
invalidRedirectRegex = regexp.MustCompile(`[/\\](?:[\s\v]*|\.{1,2})[/\\]`)
)
// allowedRoute manages method + path based allowlists
type allowedRoute struct {
method string
pathRegex *regexp.Regexp
}
// OAuthProxy is the main authentication proxy
type OAuthProxy struct {
CookieSeed string
@ -70,6 +76,7 @@ type OAuthProxy struct {
AuthOnlyPath string
UserInfoPath string
allowedRoutes []*allowedRoute
redirectURL *url.URL // the url to receive requests at
whitelistDomains []string
provider providers.Provider
@ -90,13 +97,11 @@ type OAuthProxy struct {
SetAuthorization bool
PassAuthorization bool
PreferEmailToUser bool
skipAuthRegex []string
skipAuthPreflight bool
skipAuthStripHeaders bool
skipJwtBearerTokens bool
mainJwtBearerVerifier *oidc.IDTokenVerifier
extraJwtBearerVerifiers []*oidc.IDTokenVerifier
compiledRegex []*regexp.Regexp
templates *template.Template
realClientIPParser ipapi.RealClientIPParser
trustedIPs *ip.NetSet
@ -121,10 +126,6 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
return nil, fmt.Errorf("error initialising upstream proxy: %v", err)
}
for _, u := range opts.GetCompiledRegex() {
logger.Printf("compiled skip-auth-regex => %q", u)
}
if opts.SkipJwtBearerTokens {
logger.Printf("Skipping JWT tokens from configured OIDC issuer: %q", opts.OIDCIssuerURL)
for _, issuer := range opts.ExtraJwtIssuers {
@ -163,6 +164,11 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
}
}
allowedRoutes, err := buildRoutesAllowlist(opts)
if err != nil {
return nil, err
}
sessionChain := buildSessionChain(opts, sessionStore, basicAuthValidator)
return &OAuthProxy{
@ -192,14 +198,13 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
sessionStore: sessionStore,
serveMux: upstreamProxy,
redirectURL: redirectURL,
allowedRoutes: allowedRoutes,
whitelistDomains: opts.WhitelistDomains,
skipAuthRegex: opts.SkipAuthRegex,
skipAuthPreflight: opts.SkipAuthPreflight,
skipAuthStripHeaders: opts.SkipAuthStripHeaders,
skipJwtBearerTokens: opts.SkipJwtBearerTokens,
mainJwtBearerVerifier: opts.GetOIDCVerifier(),
extraJwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
compiledRegex: opts.GetCompiledRegex(),
realClientIPParser: opts.GetRealClientIPParser(),
SetXAuthRequest: opts.SetXAuthRequest,
PassBasicAuth: opts.PassBasicAuth,
@ -277,6 +282,51 @@ func buildSignInMessage(opts *options.Options) string {
return msg
}
// buildRoutesAllowlist builds an []allowedRoute list from either the legacy
// SkipAuthRegex option (paths only support) or newer SkipAuthRoutes option
// (method=path support)
func buildRoutesAllowlist(opts *options.Options) ([]*allowedRoute, error) {
var routes []*allowedRoute
for _, path := range opts.SkipAuthRegex {
compiledRegex, err := regexp.Compile(path)
if err != nil {
return nil, err
}
routes = append(routes, &allowedRoute{
method: "",
pathRegex: compiledRegex,
})
}
for _, methodPath := range opts.SkipAuthRoutes {
var (
method string
path string
)
parts := strings.Split(methodPath, "=")
if len(parts) == 1 {
method = ""
path = parts[0]
} else {
method = strings.ToUpper(parts[0])
path = strings.Join(parts[1:], "=")
}
compiledRegex, err := regexp.Compile(path)
if err != nil {
return nil, err
}
routes = append(routes, &allowedRoute{
method: method,
pathRegex: compiledRegex,
})
}
return routes, nil
}
// GetRedirectURI returns the redirectURL that the upstream OAuth Provider will
// redirect clients to once authenticated
func (p *OAuthProxy) GetRedirectURI(host string) string {
@ -584,16 +634,16 @@ func (p *OAuthProxy) IsValidRedirect(redirect string) bool {
}
}
// IsWhitelistedRequest is used to check if auth should be skipped for this request
func (p *OAuthProxy) IsWhitelistedRequest(req *http.Request) bool {
// IsAllowedRequest is used to check if auth should be skipped for this request
func (p *OAuthProxy) IsAllowedRequest(req *http.Request) bool {
isPreflightRequestAllowed := p.skipAuthPreflight && req.Method == "OPTIONS"
return isPreflightRequestAllowed || p.IsWhitelistedPath(req.URL.Path) || p.IsTrustedIP(req)
return isPreflightRequestAllowed || p.isAllowedRoute(req) || p.IsTrustedIP(req)
}
// IsWhitelistedPath is used to check if the request path is allowed without auth
func (p *OAuthProxy) IsWhitelistedPath(path string) bool {
for _, u := range p.compiledRegex {
if u.MatchString(path) {
// IsAllowedRoute is used to check if the request method & path is allowed without auth
func (p *OAuthProxy) isAllowedRoute(req *http.Request) bool {
for _, route := range p.allowedRoutes {
if (route.method == "" || req.Method == route.method) && route.pathRegex.MatchString(req.URL.Path) {
return true
}
}
@ -643,7 +693,7 @@ func (p *OAuthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
switch path := req.URL.Path; {
case path == p.RobotsPath:
p.RobotsTxt(rw)
case p.IsWhitelistedRequest(req):
case p.IsAllowedRequest(req):
p.SkipAuthProxy(rw, req)
case path == p.SignInPath:
p.SignIn(rw, req)
@ -831,7 +881,7 @@ func (p *OAuthProxy) AuthenticateOnly(rw http.ResponseWriter, req *http.Request)
rw.WriteHeader(http.StatusAccepted)
}
// SkipAuthProxy proxies whitelisted requests and skips authentication
// SkipAuthProxy proxies allowlisted requests and skips authentication
func (p *OAuthProxy) SkipAuthProxy(rw http.ResponseWriter, req *http.Request) {
if p.skipAuthStripHeaders {
p.stripAuthHeaders(req)
@ -1026,7 +1076,7 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
}
}
// stripAuthHeaders removes Auth headers for whitelisted routes from skipAuthRegex
// stripAuthHeaders removes Auth headers for allowlisted routes from skipAuthRegex
func (p *OAuthProxy) stripAuthHeaders(req *http.Request) {
if p.PassBasicAuth {
req.Header.Del("X-Forwarded-User")

View File

@ -3,7 +3,6 @@ package options
import (
"crypto"
"net/url"
"regexp"
oidc "github.com/coreos/go-oidc"
ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
@ -67,6 +66,7 @@ type Options struct {
UpstreamServers Upstreams `cfg:",internal"`
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
SkipAuthRoutes []string `flag:"skip-auth-route" cfg:"skip_auth_routes"`
SkipAuthStripHeaders bool `flag:"skip-auth-strip-headers" cfg:"skip_auth_strip_headers"`
SkipJwtBearerTokens bool `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens"`
ExtraJwtIssuers []string `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers"`
@ -114,7 +114,6 @@ type Options struct {
// internal values that are set after config validation
redirectURL *url.URL
compiledRegex []*regexp.Regexp
provider providers.Provider
signatureData *SignatureData
oidcVerifier *oidc.IDTokenVerifier
@ -124,7 +123,6 @@ type Options struct {
// Options for Getting internal values
func (o *Options) GetRedirectURL() *url.URL { return o.redirectURL }
func (o *Options) GetCompiledRegex() []*regexp.Regexp { return o.compiledRegex }
func (o *Options) GetProvider() providers.Provider { return o.provider }
func (o *Options) GetSignatureData() *SignatureData { return o.signatureData }
func (o *Options) GetOIDCVerifier() *oidc.IDTokenVerifier { return o.oidcVerifier }
@ -133,7 +131,6 @@ func (o *Options) GetRealClientIPParser() ipapi.RealClientIPParser { return o.re
// Options for Setting internal values
func (o *Options) SetRedirectURL(s *url.URL) { o.redirectURL = s }
func (o *Options) SetCompiledRegex(s []*regexp.Regexp) { o.compiledRegex = s }
func (o *Options) SetProvider(s providers.Provider) { o.provider = s }
func (o *Options) SetSignatureData(s *SignatureData) { o.signatureData = s }
func (o *Options) SetOIDCVerifier(s *oidc.IDTokenVerifier) { o.oidcVerifier = s }
@ -195,8 +192,9 @@ func NewFlagSet() *pflag.FlagSet {
flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
flagSet.Bool("pass-authorization-header", false, "pass the Authorization Header to upstream")
flagSet.Bool("set-authorization-header", false, "set Authorization response headers (useful in Nginx auth_request mode)")
flagSet.StringSlice("skip-auth-regex", []string{}, "bypass authentication for requests path's that match (may be given multiple times)")
flagSet.Bool("skip-auth-strip-headers", false, "strips X-Forwarded-* style authentication headers & Authorization header if they would be set by oauth2-proxy for request paths in --skip-auth-regex")
flagSet.StringSlice("skip-auth-regex", []string{}, "(DEPRECATED for --skip-auth-route) bypass authentication for requests path's that match (may be given multiple times)")
flagSet.StringSlice("skip-auth-route", []string{}, "bypass authentication for requests that match the method & path. Format: method=path_regex OR path_regex alone for all methods")
flagSet.Bool("skip-auth-strip-headers", false, "strips `X-Forwarded-*` style authentication headers & `Authorization` header if they would be set by oauth2-proxy for allowlisted requests (`--skip-auth-route`, `--skip-auth-regex`, `--skip-auth-preflight`, `--trusted-ip`)")
flagSet.Bool("skip-provider-button", false, "will skip sign-in-page to directly reach the next step: oauth/start")
flagSet.Bool("skip-auth-preflight", false, "will skip authentication for OPTIONS requests")
flagSet.Bool("ssl-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS providers")

View File

@ -0,0 +1,70 @@
package validation
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/pkg/ip"
)
func validateAllowlists(o *options.Options) []string {
msgs := []string{}
msgs = append(msgs, validateRoutes(o)...)
msgs = append(msgs, validateRegexes(o)...)
msgs = append(msgs, validateTrustedIPs(o)...)
if len(o.TrustedIPs) > 0 && o.ReverseProxy {
_, err := fmt.Fprintln(os.Stderr, "WARNING: mixing --trusted-ip with --reverse-proxy is a potential security vulnerability. An attacker can inject a trusted IP into an X-Real-IP or X-Forwarded-For header if they aren't properly protected outside of oauth2-proxy")
if err != nil {
panic(err)
}
}
return msgs
}
// validateRoutes validates method=path routes passed with options.SkipAuthRoutes
func validateRoutes(o *options.Options) []string {
msgs := []string{}
for _, route := range o.SkipAuthRoutes {
var regex string
parts := strings.Split(route, "=")
if len(parts) == 1 {
regex = parts[0]
} else {
regex = strings.Join(parts[1:], "=")
}
_, err := regexp.Compile(regex)
if err != nil {
msgs = append(msgs, fmt.Sprintf("error compiling regex /%s/: %v", regex, err))
}
}
return msgs
}
// validateRegex validates regex paths passed with options.SkipAuthRegex
func validateRegexes(o *options.Options) []string {
msgs := []string{}
for _, regex := range o.SkipAuthRegex {
_, err := regexp.Compile(regex)
if err != nil {
msgs = append(msgs, fmt.Sprintf("error compiling regex /%s/: %v", regex, err))
}
}
return msgs
}
// validateTrustedIPs validates IP/CIDRs for IP based allowlists
func validateTrustedIPs(o *options.Options) []string {
msgs := []string{}
for i, ipStr := range o.TrustedIPs {
if nil == ip.ParseIPNet(ipStr) {
msgs = append(msgs, fmt.Sprintf("trusted_ips[%d] (%s) could not be recognized", i, ipStr))
}
}
return msgs
}

View File

@ -0,0 +1,149 @@
package validation
import (
"testing"
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
"github.com/stretchr/testify/assert"
)
func Test_validateAllowlists(t *testing.T) {
opts := &options.Options{
SkipAuthRoutes: []string{
"POST=/foo/bar",
"PUT=^/foo/bar$",
},
SkipAuthRegex: []string{"/foo/baz"},
TrustedIPs: []string{
"10.32.0.1/32",
"43.36.201.0/24",
},
}
assert.Equal(t, []string{}, validateAllowlists(opts))
}
func Test_validateRoutes(t *testing.T) {
testCases := map[string]struct {
Regexes []string
Expected []string
}{
"Valid regex routes": {
Regexes: []string{
"/foo",
"POST=/foo/bar",
"PUT=^/foo/bar$",
"DELETE=/crazy/(?:regex)?/[^/]+/stuff$",
},
Expected: []string{},
},
"Bad regexes do not compile": {
Regexes: []string{
"POST=/(foo",
"OPTIONS=/foo/bar)",
"GET=^]/foo/bar[$",
"GET=^]/foo/bar[$",
},
Expected: []string{
"error compiling regex //(foo/: error parsing regexp: missing closing ): `/(foo`",
"error compiling regex //foo/bar)/: error parsing regexp: unexpected ): `/foo/bar)`",
"error compiling regex /^]/foo/bar[$/: error parsing regexp: missing closing ]: `[$`",
"error compiling regex /^]/foo/bar[$/: error parsing regexp: missing closing ]: `[$`",
},
},
}
for testName, tc := range testCases {
t.Run(testName, func(t *testing.T) {
opts := &options.Options{
SkipAuthRoutes: tc.Regexes,
}
msgs := validateRoutes(opts)
assert.Equal(t, tc.Expected, msgs)
})
}
}
func Test_validateRegexes(t *testing.T) {
testCases := map[string]struct {
Regexes []string
Expected []string
}{
"Valid regex routes": {
Regexes: []string{
"/foo",
"/foo/bar",
"^/foo/bar$",
"/crazy/(?:regex)?/[^/]+/stuff$",
},
Expected: []string{},
},
"Bad regexes do not compile": {
Regexes: []string{
"/(foo",
"/foo/bar)",
"^]/foo/bar[$",
"^]/foo/bar[$",
},
Expected: []string{
"error compiling regex //(foo/: error parsing regexp: missing closing ): `/(foo`",
"error compiling regex //foo/bar)/: error parsing regexp: unexpected ): `/foo/bar)`",
"error compiling regex /^]/foo/bar[$/: error parsing regexp: missing closing ]: `[$`",
"error compiling regex /^]/foo/bar[$/: error parsing regexp: missing closing ]: `[$`",
},
},
}
for testName, tc := range testCases {
t.Run(testName, func(t *testing.T) {
opts := &options.Options{
SkipAuthRegex: tc.Regexes,
}
msgs := validateRegexes(opts)
assert.Equal(t, tc.Expected, msgs)
})
}
}
func Test_validateTrustedIPs(t *testing.T) {
testCases := map[string]struct {
TrustedIPs []string
Expected []string
}{
"Non-overlapping valid IPs": {
TrustedIPs: []string{
"127.0.0.1",
"10.32.0.1/32",
"43.36.201.0/24",
"::1",
"2a12:105:ee7:9234:0:0:0:0/64",
},
Expected: []string{},
},
"Overlapping valid IPs": {
TrustedIPs: []string{
"135.180.78.199",
"135.180.78.199/32",
"d910:a5a1:16f8:ddf5:e5b9:5cef:a65e:41f4",
"d910:a5a1:16f8:ddf5:e5b9:5cef:a65e:41f4/128",
},
Expected: []string{},
},
"Invalid IPs": {
TrustedIPs: []string{"[::1]", "alkwlkbn/32"},
Expected: []string{
"trusted_ips[0] ([::1]) could not be recognized",
"trusted_ips[1] (alkwlkbn/32) could not be recognized",
},
},
}
for testName, tc := range testCases {
t.Run(testName, func(t *testing.T) {
opts := &options.Options{
TrustedIPs: tc.TrustedIPs,
}
msgs := validateTrustedIPs(opts)
assert.Equal(t, tc.Expected, msgs)
})
}
}

View File

@ -9,7 +9,6 @@ import (
"net/http"
"net/url"
"os"
"regexp"
"strings"
"github.com/coreos/go-oidc"
@ -184,15 +183,6 @@ func Validate(o *options.Options) error {
o.SetRedirectURL(redirectURL)
msgs = append(msgs, validateUpstreams(o.UpstreamServers)...)
for _, u := range o.SkipAuthRegex {
compiledRegex, err := regexp.Compile(u)
if err != nil {
msgs = append(msgs, fmt.Sprintf("error compiling regex=%q %s", u, err))
continue
}
o.SetCompiledRegex(append(o.GetCompiledRegex(), compiledRegex))
}
msgs = parseProviderInfo(o, msgs)
if len(o.GoogleGroups) > 0 || o.GoogleAdminEmail != "" || o.GoogleServiceAccountJSON != "" {
@ -223,18 +213,8 @@ func Validate(o *options.Options) error {
})
}
if len(o.TrustedIPs) > 0 && o.ReverseProxy {
_, err := fmt.Fprintln(os.Stderr, "WARNING: trusting of IPs with --reverse-proxy poses risks if a header spoofing attack is possible.")
if err != nil {
panic(err)
}
}
for i, ipStr := range o.TrustedIPs {
if nil == ip.ParseIPNet(ipStr) {
msgs = append(msgs, fmt.Sprintf("trusted_ips[%d] (%s) could not be recognized", i, ipStr))
}
}
// Do this after ReverseProxy validation for TrustedIP coordinated checks
msgs = append(msgs, validateAllowlists(o)...)
if len(msgs) != 0 {
return fmt.Errorf("invalid configuration:\n %s",

View File

@ -2,7 +2,6 @@ package validation
import (
"crypto"
"errors"
"io/ioutil"
"net/url"
"os"
@ -78,12 +77,19 @@ func TestClientSecretFileOption(t *testing.T) {
if err != nil {
t.Fatalf("failed to create temp file: %v", err)
}
f.WriteString("testcase")
_, err = f.WriteString("testcase")
if err != nil {
t.Fatalf("failed to write to temp file: %v", err)
}
if err := f.Close(); err != nil {
t.Fatalf("failed to close temp file: %v", err)
}
clientSecretFileName := f.Name()
defer os.Remove(clientSecretFileName)
defer func(t *testing.T) {
if err := os.Remove(clientSecretFileName); err != nil {
t.Fatalf("failed to delete temp file: %v", err)
}
}(t)
o := options.NewOptions()
o.Cookie.Secret = cookieSecret
@ -144,41 +150,6 @@ func TestRedirectURL(t *testing.T) {
assert.Equal(t, expected, o.GetRedirectURL())
}
func TestCompiledRegex(t *testing.T) {
o := testOptions()
regexps := []string{"/foo/.*", "/ba[rz]/quux"}
o.SkipAuthRegex = regexps
assert.Equal(t, nil, Validate(o))
actual := make([]string, 0)
for _, regex := range o.GetCompiledRegex() {
actual = append(actual, regex.String())
}
assert.Equal(t, regexps, actual)
}
func TestCompiledRegexError(t *testing.T) {
o := testOptions()
o.SkipAuthRegex = []string{"(foobaz", "barquux)"}
err := Validate(o)
assert.NotEqual(t, nil, err)
expected := errorMsg([]string{
"error compiling regex=\"(foobaz\" error parsing regexp: " +
"missing closing ): `(foobaz`",
"error compiling regex=\"barquux)\" error parsing regexp: " +
"unexpected ): `barquux)`"})
assert.Equal(t, expected, err.Error())
o.SkipAuthRegex = []string{"foobaz", "barquux)"}
err = Validate(o)
assert.NotEqual(t, nil, err)
expected = errorMsg([]string{
"error compiling regex=\"barquux)\" error parsing regexp: " +
"unexpected ): `barquux)`"})
assert.Equal(t, expected, err.Error())
}
func TestDefaultProviderApiSettings(t *testing.T) {
o := testOptions()
assert.Equal(t, nil, Validate(o))
@ -337,45 +308,6 @@ func TestRealClientIPHeader(t *testing.T) {
assert.Nil(t, o.GetRealClientIPParser())
}
func TestIPCIDRSetOption(t *testing.T) {
tests := []struct {
name string
trustedIPs []string
err error
}{
{
"TestSomeIPs",
[]string{"127.0.0.1", "10.32.0.1/32", "43.36.201.0/24", "::1", "2a12:105:ee7:9234:0:0:0:0/64"},
nil,
}, {
"TestOverlappingIPs",
[]string{"135.180.78.199", "135.180.78.199/32", "d910:a5a1:16f8:ddf5:e5b9:5cef:a65e:41f4", "d910:a5a1:16f8:ddf5:e5b9:5cef:a65e:41f4/128"},
nil,
}, {
"TestInvalidIPs",
[]string{"[::1]", "alkwlkbn/32"},
errors.New(
"invalid configuration:\n" +
" trusted_ips[0] ([::1]) could not be recognized\n" +
" trusted_ips[1] (alkwlkbn/32) could not be recognized",
),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := testOptions()
o.TrustedIPs = tt.trustedIPs
err := Validate(o)
if tt.err == nil {
assert.Nil(t, err)
} else {
assert.Equal(t, tt.err.Error(), err.Error())
}
})
}
}
func TestProviderCAFilesError(t *testing.T) {
file, err := ioutil.TempFile("", "absent.*.crt")
assert.NoError(t, err)