proxy: restrict programmatic URLs to localhost (#2047)

Co-authored-by: Caleb Doxsey <cdoxsey@pomerium.com>
This commit is contained in:
Travis Groth 2021-03-31 12:52:20 -04:00 committed by GitHub
parent ec60fcd32f
commit fff798d0e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 802 additions and 107 deletions

View file

@ -270,6 +270,9 @@ type Options struct {
// SkipXffAppend instructs proxy not to append its IP address to x-forwarded-for header. // SkipXffAppend instructs proxy not to append its IP address to x-forwarded-for header.
// see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html?highlight=skip_xff_append#x-forwarded-for // see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html?highlight=skip_xff_append#x-forwarded-for
SkipXffAppend bool `mapstructure:"skip_xff_append" yaml:"skip_xff_append,omitempty" json:"skip_xff_append,omitempty"` SkipXffAppend bool `mapstructure:"skip_xff_append" yaml:"skip_xff_append,omitempty" json:"skip_xff_append,omitempty"`
// ProgrammaticRedirectDomainWhitelist restricts the allowed redirect URLs when using programmatic login.
ProgrammaticRedirectDomainWhitelist []string `mapstructure:"programmatic_redirect_domain_whitelist" yaml:"programmatic_redirect_domain_whitelist,omitempty" json:"programmatic_redirect_domain_whitelist,omitempty"` //nolint
} }
type certificateFilePair struct { type certificateFilePair struct {
@ -312,8 +315,9 @@ var defaultOptions = Options{
AutocertOptions: AutocertOptions{ AutocertOptions: AutocertOptions{
Folder: dataDir(), Folder: dataDir(),
}, },
DataBrokerStorageType: "memory", DataBrokerStorageType: "memory",
SkipXffAppend: false, SkipXffAppend: false,
ProgrammaticRedirectDomainWhitelist: []string{"localhost"},
} }
// NewDefaultOptions returns a copy the default options. It's the caller's // NewDefaultOptions returns a copy the default options. It's the caller's
@ -949,6 +953,9 @@ func (o *Options) ApplySettings(settings *config.Settings) {
if settings.SkipXffAppend != nil { if settings.SkipXffAppend != nil {
o.SkipXffAppend = settings.GetSkipXffAppend() o.SkipXffAppend = settings.GetSkipXffAppend()
} }
if len(settings.ProgrammaticRedirectDomainWhitelist) > 0 {
o.ProgrammaticRedirectDomainWhitelist = settings.GetProgrammaticRedirectDomainWhitelist()
}
} }
// handleConfigUpdate takes configuration file, an existing options struct, and // handleConfigUpdate takes configuration file, an existing options struct, and

View file

@ -236,7 +236,7 @@ func Test_Checksum(t *testing.T) {
func TestOptionsFromViper(t *testing.T) { func TestOptionsFromViper(t *testing.T) {
opts := []cmp.Option{ opts := []cmp.Option{
cmpopts.IgnoreFields(Options{}, "CookieSecret", "GRPCInsecure", "GRPCAddr", "DataBrokerURLString", "DataBrokerURL", "AuthorizeURL", "AuthorizeURLString", "DefaultUpstreamTimeout", "CookieExpire", "Services", "Addr", "RefreshCooldown", "LogLevel", "KeyFile", "CertFile", "SharedKey", "ReadTimeout", "IdleTimeout", "GRPCClientTimeout", "GRPCClientDNSRoundRobin", "TracingSampleRate"), cmpopts.IgnoreFields(Options{}, "CookieSecret", "GRPCInsecure", "GRPCAddr", "DataBrokerURLString", "DataBrokerURL", "AuthorizeURL", "AuthorizeURLString", "DefaultUpstreamTimeout", "CookieExpire", "Services", "Addr", "RefreshCooldown", "LogLevel", "KeyFile", "CertFile", "SharedKey", "ReadTimeout", "IdleTimeout", "GRPCClientTimeout", "GRPCClientDNSRoundRobin", "TracingSampleRate", "ProgrammaticRedirectDomainWhitelist"),
cmpopts.IgnoreFields(Policy{}, "Source", "EnvoyOpts"), cmpopts.IgnoreFields(Policy{}, "Source", "EnvoyOpts"),
cmpOptIgnoreUnexported, cmpOptIgnoreUnexported,
} }

View file

@ -23,6 +23,8 @@ $ curl "https://verify.example.com/.pomerium/api/v1/login?pomerium_redirect_uri=
https://authenticate.example.com/.pomerium/sign_in?pomerium_redirect_uri=http%3A%2F%2Flocalhost%3Fpomerium_callback_uri%3Dhttps%253A%252F%verify.corp.example%252F.pomerium%252Fapi%252Fv1%252Flogin%253Fpomerium_redirect_uri%253Dhttp%253A%252F%252Flocalhost&sig=hsLuzJctmgsN4kbMeQL16fe_FahjDBEcX0_kPYfg8bs%3D&ts=1573262981 https://authenticate.example.com/.pomerium/sign_in?pomerium_redirect_uri=http%3A%2F%2Flocalhost%3Fpomerium_callback_uri%3Dhttps%253A%252F%verify.corp.example%252F.pomerium%252Fapi%252Fv1%252Flogin%253Fpomerium_redirect_uri%253Dhttp%253A%252F%252Flocalhost&sig=hsLuzJctmgsN4kbMeQL16fe_FahjDBEcX0_kPYfg8bs%3D&ts=1573262981
``` ```
By default only `localhost` URLs are allowed as the `pomerium_redirect_uri`. This can be customized with the `programmatic_redirect_domain_whitelist` option.
### Callback handler ### Callback handler
It is the script or application's responsibility to create a HTTP callback handler. Authenticated sessions are returned in the form of a [callback](https://developer.okta.com/docs/concepts/auth-overview/#what-kind-of-client-are-you-building) from pomerium to a HTTP server. This is the `pomerium_redirect_uri` value used to build login API's URL, and represents the URL of a (usually local) HTTP server responsible for receiving the resulting user session in the form of `pomerium_jwt` query parameters. It is the script or application's responsibility to create a HTTP callback handler. Authenticated sessions are returned in the form of a [callback](https://developer.okta.com/docs/concepts/auth-overview/#what-kind-of-client-are-you-building) from pomerium to a HTTP server. This is the `pomerium_redirect_uri` value used to build login API's URL, and represents the URL of a (usually local) HTTP server responsible for receiving the resulting user session in the form of `pomerium_jwt` query parameters.

View file

@ -5,6 +5,13 @@ description: >-
for Pomerium. Please read it carefully. for Pomerium. Please read it carefully.
--- ---
# Since 0.13.0
## Breaking
### Programmatic login domain whitelist
Programmatic login now restricts the allowed redirect URL domains. By default this is set to `localhost`, but can be changed via the `programmatic_redirect_domain_whitelist` option.
# Since 0.12.0 # Since 0.12.0
## New ## New

View file

@ -836,6 +836,15 @@ Use this option if you previously relied on `x-pomerium-authenticated-user-{emai
Secure service communication can fail if the external certificate does not match the internally routed service hostname/[SNI](https://en.wikipedia.org/wiki/Server_Name_Indication). This setting allows you to override that value. Secure service communication can fail if the external certificate does not match the internally routed service hostname/[SNI](https://en.wikipedia.org/wiki/Server_Name_Indication). This setting allows you to override that value.
### Programmatic Redirect Domain Whitelist
- Config File Key: `programmatic_redirect_domain_whitelist`
- Type: array of `string`
- Optional
- Default: `localhost`
The programmatic redirect domain whitelist is used to restrict the allowed redirect URLs when using programmatic login. By default only `localhost` URLs are allowed.
### Refresh Cooldown ### Refresh Cooldown
- Environmental Variable: `REFRESH_COOLDOWN` - Environmental Variable: `REFRESH_COOLDOWN`
- Config File Key: `refresh_cooldown` - Config File Key: `refresh_cooldown`

View file

@ -944,6 +944,15 @@ settings:
Secure service communication can fail if the external certificate does not match the internally routed service hostname/[SNI](https://en.wikipedia.org/wiki/Server_Name_Indication). This setting allows you to override that value. Secure service communication can fail if the external certificate does not match the internally routed service hostname/[SNI](https://en.wikipedia.org/wiki/Server_Name_Indication). This setting allows you to override that value.
shortdoc: | shortdoc: |
Secure service communication can fail if the external certificate does not match the internally routed service hostname/SNI. Secure service communication can fail if the external certificate does not match the internally routed service hostname/SNI.
- name: "Programmatic Redirect Domain Whitelist"
keys: ["programmatic_redirect_domain_whitelist"]
attributes: |
- Config File Key: `programmatic_redirect_domain_whitelist`
- Type: array of `string`
- Optional
- Default: `localhost`
doc: |
The programmatic redirect domain whitelist is used to restrict the allowed redirect URLs when using programmatic login. By default only `localhost` URLs are allowed.
- name: "Refresh Cooldown" - name: "Refresh Cooldown"
keys: ["refresh_cooldown"] keys: ["refresh_cooldown"]
attributes: | attributes: |

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
@ -87,10 +88,15 @@ func Authenticate(ctx context.Context, client *http.Client, url *url.URL, option
originalHostname := url.Hostname() originalHostname := url.Hostname()
var err error var err error
// Serve a local callback for programmatic redirect flow
srv := httptest.NewUnstartedServer(http.RedirectHandler(url.String(), http.StatusFound))
defer srv.Close()
if cfg.apiPath != "" { if cfg.apiPath != "" {
srv.Start()
apiLogin := url apiLogin := url
q := apiLogin.Query() q := apiLogin.Query()
q.Set(urlutil.QueryRedirectURI, url.String()) q.Set(urlutil.QueryRedirectURI, srv.URL)
apiLogin.RawQuery = q.Encode() apiLogin.RawQuery = q.Encode()
apiLogin.Path = cfg.apiPath apiLogin.Path = cfg.apiPath
@ -225,6 +231,22 @@ func Authenticate(ctx context.Context, client *http.Client, url *url.URL, option
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err) return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
} }
// Programmatic flow: Follow redirect from local callback
if cfg.apiPath != "" {
req, err = requestFromRedirectResponse(ctx, res, req)
if err != nil {
return nil, fmt.Errorf("expected redirect to %s: %w", srv.URL, err)
}
res, err = client.Do(req)
if err != nil {
return nil, err
}
req, err = requestFromRedirectResponse(ctx, res, req)
if err != nil {
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
}
}
return client.Do(req) return client.Do(req)
} }

View file

@ -0,0 +1,35 @@
package urlutil
import (
"net"
"net/url"
)
// IsRedirectAllowed returns true if the redirect URL is whitelisted.
func IsRedirectAllowed(redirectURL *url.URL, whitelistDomains []string) bool {
if !(redirectURL.Scheme == "http" || redirectURL.Scheme == "https") {
return false
}
for _, domain := range whitelistDomains {
if domain == "localhost" && IsLoopback(redirectURL) {
return true
} else if redirectURL.Hostname() == domain {
return true
}
}
return false
}
// IsLoopback returns true if the given URL corresponds with a loopback address.
func IsLoopback(u *url.URL) bool {
hostname := u.Hostname()
if hostname == "localhost" {
return true
}
if ip := net.ParseIP(hostname); ip != nil {
return ip.IsLoopback()
}
return false
}

View file

@ -0,0 +1,546 @@
package urlutil
import (
"net/url"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIsRedirectAllowed(t *testing.T) {
// from: https://raw.githubusercontent.com/random-robbie/open-redirect/master/payloads.txt
rawurls := strings.Fields(`
&%0d%0a1Location:https://google.com
@google.com
@https://www.google.com
%2f%2e%2e
crlftest%0dLocation:https://google.com
/https:/%5cblackfan.ru/
//example.com@google.com/%2f..
///google.com/%2f..
///example.com@google.com/%2f..
////google.com/%2f..
////example.com@google.com/%2f..
/x:1/:///%01javascript:alert(document.cookie)/
https://google.com/%2f..
https://example.com@google.com/%2f..
/https://google.com/%2f..
/https://example.com@google.com/%2f.//example.com@google.com/%2f..
///google.com/%2f..
///example.com@google.com/%2f..
////google.com/%2f..
////example.com@google.com/%2f..
https://google.com/%2f..
https://example.com@google.com/%2f..
/https://google.com/%2f..
/https://example.com@google.com/%2f..
//google.com/%2f%2e%2e
//example.com@google.com/%2f%2e%2e
///google.com/%2f%2e%2e
///example.com@google.com/%2f%2e%2e
////google.com/%2f%2e%2e
////example.com@google.com/%2f%2e%2e
https://google.com/%2f%2e%2e
https://example.com@google.com/%2f%2e%2e
/https://google.com/%2f%2e%2e
/https://example.com@google.com/%2f%2e%2e
//google.com/
//example.com@google.com/
///google.com/
///example.com@google.com/
////google.com/
////example.com@google.com/
https://google.com/
https://example.com@google.com/
/https://google.com/
/https://example.com@google.com/
//google.com//
//example.com@google.com//
///google.com//
///example.com@google.com//
////google.com//
////example.com@google.com//
https://google.com//
https://example.com@google.com//
//https://google.com//
//https://example.com@google.com//
//google.com/%2e%2e%2f
//example.com@google.com/%2e%2e%2f
///google.com/%2e%2e%2f
///example.com@google.com/%2e%2e%2f
////google.com/%2e%2e%2f
////example.com@google.com/%2e%2e%2f
https://google.com/%2e%2e%2f
https://example.com@google.com/%2e%2e%2f
//https://google.com/%2e%2e%2f
//https://example.com@google.com/%2e%2e%2f
///google.com/%2e%2e
///example.com@google.com/%2e%2e
////google.com/%2e%2e
////example.com@google.com/%2e%2e
https:///google.com/%2e%2e
https:///example.com@google.com/%2e%2e
//https:///google.com/%2e%2e
//example.com@https:///google.com/%2e%2e
/https://google.com/%2e%2e
/https://example.com@google.com/%2e%2e
///google.com/%2f%2e%2e
///example.com@google.com/%2f%2e%2e
////google.com/%2f%2e%2e
////example.com@google.com/%2f%2e%2e
https:///google.com/%2f%2e%2e
https:///example.com@google.com/%2f%2e%2e
/https://google.com/%2f%2e%2e
/https://example.com@google.com/%2f%2e%2e
/https:///google.com/%2f%2e%2e
/https:///example.com@google.com/%2f%2e%2e
/%09/google.com
/%09/example.com@google.com
//%09/google.com
//%09/example.com@google.com
///%09/google.com
///%09/example.com@google.com
////%09/google.com
////%09/example.com@google.com
https://%09/google.com
https://%09/example.com@google.com
/%5cgoogle.com
/%5cexample.com@google.com
//%5cgoogle.com
//%5cexample.com@google.com
///%5cgoogle.com
///%5cexample.com@google.com
////%5cgoogle.com
////%5cexample.com@google.com
https://%5cgoogle.com
https://%5cexample.com@google.com
/https://%5cgoogle.com
/https://%5cexample.com@google.com
https://google.com
https://example.com@google.com
//google.com
https:google.com
//google%E3%80%82com
\/\/google.com/
/\/google.com/
//google%00.com
http://0xd8.0x3a.0xd6.0xce
http://example.com@0xd8.0x3a.0xd6.0xce
http://3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce
http://XY>.7d8T\205pZM@0xd8.0x3a.0xd6.0xce
http://0xd83ad6ce
http://example.com@0xd83ad6ce
http://3H6k7lIAiqjfNeN@0xd83ad6ce
http://XY>.7d8T\205pZM@0xd83ad6ce
http://3627734734
http://example.com@3627734734
http://3H6k7lIAiqjfNeN@3627734734
http://XY>.7d8T\205pZM@3627734734
http://472.314.470.462
http://example.com@472.314.470.462
http://3H6k7lIAiqjfNeN@472.314.470.462
http://XY>.7d8T\205pZM@472.314.470.462
http://0330.072.0326.0316
http://example.com@0330.072.0326.0316
http://3H6k7lIAiqjfNeN@0330.072.0326.0316
http://XY>.7d8T\205pZM@0330.072.0326.0316
http://00330.00072.0000326.00000316
http://example.com@00330.00072.0000326.00000316
http://3H6k7lIAiqjfNeN@00330.00072.0000326.00000316
http://XY>.7d8T\205pZM@00330.00072.0000326.00000316
http://[::216.58.214.206]
http://example.com@[::216.58.214.206]
http://3H6k7lIAiqjfNeN@[::216.58.214.206]
http://XY>.7d8T\205pZM@[::216.58.214.206]
http://[::ffff:216.58.214.206]
http://example.com@[::ffff:216.58.214.206]
http://3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]
http://XY>.7d8T\205pZM@[::ffff:216.58.214.206]
http://0xd8.072.54990
http://example.com@0xd8.072.54990
http://3H6k7lIAiqjfNeN@0xd8.072.54990
http://XY>.7d8T\205pZM@0xd8.072.54990
http://0xd8.3856078
http://example.com@0xd8.3856078
http://3H6k7lIAiqjfNeN@0xd8.3856078
http://XY>.7d8T\205pZM@0xd8.3856078
http://00330.3856078
http://example.com@00330.3856078
http://3H6k7lIAiqjfNeN@00330.3856078
http://XY>.7d8T\205pZM@00330.3856078
http://00330.0x3a.54990
http://example.com@00330.0x3a.54990
http://3H6k7lIAiqjfNeN@00330.0x3a.54990
http://XY>.7d8T\205pZM@00330.0x3a.54990
http:0xd8.0x3a.0xd6.0xce
http:example.com@0xd8.0x3a.0xd6.0xce
http:3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce
http:XY>.7d8T\205pZM@0xd8.0x3a.0xd6.0xce
http:0xd83ad6ce
http:example.com@0xd83ad6ce
http:3H6k7lIAiqjfNeN@0xd83ad6ce
http:XY>.7d8T\205pZM@0xd83ad6ce
http:3627734734
http:example.com@3627734734
http:3H6k7lIAiqjfNeN@3627734734
http:XY>.7d8T\205pZM@3627734734
http:472.314.470.462
http:example.com@472.314.470.462
http:3H6k7lIAiqjfNeN@472.314.470.462
http:XY>.7d8T\205pZM@472.314.470.462
http:0330.072.0326.0316
http:example.com@0330.072.0326.0316
http:3H6k7lIAiqjfNeN@0330.072.0326.0316
http:XY>.7d8T\205pZM@0330.072.0326.0316
http:00330.00072.0000326.00000316
http:example.com@00330.00072.0000326.00000316
http:3H6k7lIAiqjfNeN@00330.00072.0000326.00000316
http:XY>.7d8T\205pZM@00330.00072.0000326.00000316
http:[::216.58.214.206]
http:example.com@[::216.58.214.206]
http:3H6k7lIAiqjfNeN@[::216.58.214.206]
http:XY>.7d8T\205pZM@[::216.58.214.206]
http:[::ffff:216.58.214.206]
http:example.com@[::ffff:216.58.214.206]
http:3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]
http:XY>.7d8T\205pZM@[::ffff:216.58.214.206]
http:0xd8.072.54990
http:example.com@0xd8.072.54990
http:3H6k7lIAiqjfNeN@0xd8.072.54990
http:XY>.7d8T\205pZM@0xd8.072.54990
http:0xd8.3856078
http:example.com@0xd8.3856078
http:3H6k7lIAiqjfNeN@0xd8.3856078
http:XY>.7d8T\205pZM@0xd8.3856078
http:00330.3856078
http:example.com@00330.3856078
http:3H6k7lIAiqjfNeN@00330.3856078
http:XY>.7d8T\205pZM@00330.3856078
http:00330.0x3a.54990
http:example.com@00330.0x3a.54990
http:3H6k7lIAiqjfNeN@00330.0x3a.54990
http:XY>.7d8T\205pZM@00330.0x3a.54990
〱google.com
〵google.com
ゝgoogle.com
ーgoogle.com
ーgoogle.com
/〱google.com
/〵google.com
/ゝgoogle.com
/ーgoogle.com
/ーgoogle.com
%68%74%74%70%3a%2f%2f%67%6f%6f%67%6c%65%2e%63%6f%6d
http://%67%6f%6f%67%6c%65%2e%63%6f%6d
<>//google.com
//google.com\@example.com
https://:@google.com\@example.com
http://google.com:80#@example.com/
http://google.com:80?@example.com/
http://3H6k7lIAiqjfNeN@example.com+@google.com/
http://XY>.7d8T\205pZM@example.com+@google.com/
http://3H6k7lIAiqjfNeN@example.com@google.com/
http://XY>.7d8T\205pZM@example.com@google.com/
http://example.com+&@google.com#+@example.com/
http://google.com\texample.com/
//google.com:80#@example.com/
//google.com:80?@example.com/
//3H6k7lIAiqjfNeN@example.com+@google.com/
//XY>.7d8T\205pZM@example.com+@google.com/
//3H6k7lIAiqjfNeN@example.com@google.com/
//XY>.7d8T\205pZM@example.com@google.com/
//example.com+&@google.com#+@example.com/
//google.com\texample.com/
//;@google.com
http://;@google.com
@google.com
http://google.com%2f%2f.example.com/
http://google.com%5c%5c.example.com/
http://google.com%3F.example.com/
http://google.com%23.example.com/
http://example.com:80%40google.com/
http://example.com%2egoogle.com/
/https:/%5cgoogle.com/
/http://google.com
/%2f%2fgoogle.com
/google.com/%2f%2e%2e
/http:/google.com
/.google.com
///\;@google.com
///google.com
/////google.com/
/////google.com
//google.com/%2f%2e%2e
//example.com@google.com/%2f%2e%2e
///google.com/%2f%2e%2e
///example.com@google.com/%2f%2e%2e
////google.com/%2f%2e%2e
////example.com@google.com/%2f%2e%2e
https://google.com/%2f%2e%2e
https://example.com@google.com/%2f%2e%2e
/https://google.com/%2f%2e%2e
/https://example.com@google.com/%2f%2e%2e
//google.com/
//example.com@google.com/
///google.com/
///example.com@google.com/
////google.com/
////example.com@google.com/
https://google.com/
https://example.com@google.com/
/https://google.com/
/https://example.com@google.com/
//google.com//
//example.com@google.com//
///google.com//
///example.com@google.com//
////google.com//
////example.com@google.com//
https://google.com//
https://example.com@google.com//
//https://google.com//
//https://example.com@google.com//
//google.com/%2e%2e%2f
//example.com@google.com/%2e%2e%2f
///google.com/%2e%2e%2f
///example.com@google.com/%2e%2e%2f
////google.com/%2e%2e%2f
////example.com@google.com/%2e%2e%2f
https://google.com/%2e%2e%2f
https://example.com@google.com/%2e%2e%2f
//https://google.com/%2e%2e%2f
//https://example.com@google.com/%2e%2e%2f
///google.com/%2e%2e
///example.com@google.com/%2e%2e
////google.com/%2e%2e
////example.com@google.com/%2e%2e
https:///google.com/%2e%2e
https:///example.com@google.com/%2e%2e
//https:///google.com/%2e%2e
//example.com@https:///google.com/%2e%2e
/https://google.com/%2e%2e
/https://example.com@google.com/%2e%2e
///google.com/%2f%2e%2e
///example.com@google.com/%2f%2e%2e
////google.com/%2f%2e%2e
////example.com@google.com/%2f%2e%2e
https:///google.com/%2f%2e%2e
https:///example.com@google.com/%2f%2e%2e
/https://google.com/%2f%2e%2e
/https://example.com@google.com/%2f%2e%2e
/https:///google.com/%2f%2e%2e
/https:///example.com@google.com/%2f%2e%2e
/%09/google.com
/%09/example.com@google.com
//%09/google.com
//%09/example.com@google.com
///%09/google.com
///%09/example.com@google.com
////%09/google.com
////%09/example.com@google.com
https://%09/google.com
https://%09/example.com@google.com
/%5cgoogle.com
/%5cexample.com@google.com
//%5cgoogle.com
//%5cexample.com@google.com
///%5cgoogle.com
///%5cexample.com@google.com
////%5cgoogle.com
////%5cexample.com@google.com
https://%5cgoogle.com
https://%5cexample.com@google.com
/https://%5cgoogle.com
/https://%5cexample.com@google.com
https://google.com
https://example.com@google.com
//google.com
https:google.com
//google%E3%80%82com
\/\/google.com/
/\/google.com/
//google%00.com
javascript://example.com?%a0alert%281%29
http://0xd8.0x3a.0xd6.0xce
http://example.com@0xd8.0x3a.0xd6.0xce
http://3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce
http://XY>.7d8T\205pZM@0xd8.0x3a.0xd6.0xce
http://0xd83ad6ce
http://example.com@0xd83ad6ce
http://3H6k7lIAiqjfNeN@0xd83ad6ce
http://XY>.7d8T\205pZM@0xd83ad6ce
http://3627734734
http://example.com@3627734734
http://3H6k7lIAiqjfNeN@3627734734
http://XY>.7d8T\205pZM@3627734734
http://472.314.470.462
http://example.com@472.314.470.462
http://3H6k7lIAiqjfNeN@472.314.470.462
http://XY>.7d8T\205pZM@472.314.470.462
http://0330.072.0326.0316
http://example.com@0330.072.0326.0316
http://3H6k7lIAiqjfNeN@0330.072.0326.0316
http://XY>.7d8T\205pZM@0330.072.0326.0316
http://00330.00072.0000326.00000316
http://example.com@00330.00072.0000326.00000316
http://3H6k7lIAiqjfNeN@00330.00072.0000326.00000316
http://XY>.7d8T\205pZM@00330.00072.0000326.00000316
http://[::216.58.214.206]
http://example.com@[::216.58.214.206]
http://3H6k7lIAiqjfNeN@[::216.58.214.206]
http://XY>.7d8T\205pZM@[::216.58.214.206]
http://[::ffff:216.58.214.206]
http://example.com@[::ffff:216.58.214.206]
http://3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]
http://XY>.7d8T\205pZM@[::ffff:216.58.214.206]
http://0xd8.072.54990
http://example.com@0xd8.072.54990
http://3H6k7lIAiqjfNeN@0xd8.072.54990
http://XY>.7d8T\205pZM@0xd8.072.54990
http://0xd8.3856078
http://example.com@0xd8.3856078
http://3H6k7lIAiqjfNeN@0xd8.3856078
http://XY>.7d8T\205pZM@0xd8.3856078
http://00330.3856078
http://example.com@00330.3856078
http://3H6k7lIAiqjfNeN@00330.3856078
http://XY>.7d8T\205pZM@00330.3856078
http://00330.0x3a.54990
http://example.com@00330.0x3a.54990
http://3H6k7lIAiqjfNeN@00330.0x3a.54990
http://XY>.7d8T\205pZM@00330.0x3a.54990
http:0xd8.0x3a.0xd6.0xce
http:example.com@0xd8.0x3a.0xd6.0xce
http:3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce
http:XY>.7d8T\205pZM@0xd8.0x3a.0xd6.0xce
http:0xd83ad6ce
http:example.com@0xd83ad6ce
http:3H6k7lIAiqjfNeN@0xd83ad6ce
http:XY>.7d8T\205pZM@0xd83ad6ce
http:3627734734
http:example.com@3627734734
http:3H6k7lIAiqjfNeN@3627734734
http:XY>.7d8T\205pZM@3627734734
http:472.314.470.462
http:example.com@472.314.470.462
http:3H6k7lIAiqjfNeN@472.314.470.462
http:XY>.7d8T\205pZM@472.314.470.462
http:0330.072.0326.0316
http:example.com@0330.072.0326.0316
http:3H6k7lIAiqjfNeN@0330.072.0326.0316
http:XY>.7d8T\205pZM@0330.072.0326.0316
http:00330.00072.0000326.00000316
http:example.com@00330.00072.0000326.00000316
http:3H6k7lIAiqjfNeN@00330.00072.0000326.00000316
http:XY>.7d8T\205pZM@00330.00072.0000326.00000316
http:[::216.58.214.206]
http:example.com@[::216.58.214.206]
http:3H6k7lIAiqjfNeN@[::216.58.214.206]
http:XY>.7d8T\205pZM@[::216.58.214.206]
http:[::ffff:216.58.214.206]
http:example.com@[::ffff:216.58.214.206]
http:3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]
http:XY>.7d8T\205pZM@[::ffff:216.58.214.206]
http:0xd8.072.54990
http:example.com@0xd8.072.54990
http:3H6k7lIAiqjfNeN@0xd8.072.54990
http:XY>.7d8T\205pZM@0xd8.072.54990
http:0xd8.3856078
http:example.com@0xd8.3856078
http:3H6k7lIAiqjfNeN@0xd8.3856078
http:XY>.7d8T\205pZM@0xd8.3856078
http:00330.3856078
http:example.com@00330.3856078
http:3H6k7lIAiqjfNeN@00330.3856078
http:XY>.7d8T\205pZM@00330.3856078
http:00330.0x3a.54990
http:example.com@00330.0x3a.54990
http:3H6k7lIAiqjfNeN@00330.0x3a.54990
http:XY>.7d8T\205pZM@00330.0x3a.54990
〱google.com
〵google.com
ゝgoogle.com
ーgoogle.com
ーgoogle.com
/〱google.com
/〵google.com
/ゝgoogle.com
/ーgoogle.com
/ーgoogle.com
%68%74%74%70%3a%2f%2f%67%6f%6f%67%6c%65%2e%63%6f%6d
http://%67%6f%6f%67%6c%65%2e%63%6f%6d
<>javascript:alert(1);
<>//google.com
//google.com\@example.com
https://:@google.com\@example.com
ja\nva\tscript\r:alert(1)
\j\av\a\s\cr\i\pt\:\a\l\ert\(1\)
\152\141\166\141\163\143\162\151\160\164\072alert(1)
http://google.com:80#@example.com/
http://google.com:80?@example.com/
http://3H6k7lIAiqjfNeN@example.com+@google.com/
http://XY>.7d8T\205pZM@example.com+@google.com/
http://3H6k7lIAiqjfNeN@example.com@google.com/
http://XY>.7d8T\205pZM@example.com@google.com/
http://example.com+&@google.com#+@example.com/
http://google.com\texample.com/
//google.com:80#@example.com/
//google.com:80?@example.com/
//3H6k7lIAiqjfNeN@example.com+@google.com/
//XY>.7d8T\205pZM@example.com+@google.com/
//3H6k7lIAiqjfNeN@example.com@google.com/
//XY>.7d8T\205pZM@example.com@google.com/
//example.com+&@google.com#+@example.com/
//google.com\texample.com/
//;@google.com
http://;@google.com
javascript://https://example.com/?z=%0Aalert(1)
http://google.com%2f%2f.example.com/
http://google.com%5c%5c.example.com/
http://google.com%3F.example.com/
http://google.com%23.example.com/
http://example.com:80%40google.com/
http://example.com%2egoogle.com/
/https:/%5cgoogle.com/
/http://google.com
/%2f%2fgoogle.com
/google.com/%2f%2e%2e
/http:/google.com
/.google.com
///\;@google.com
///google.com
/////google.com/
/////google.com
`)
for _, rawurl := range rawurls {
u, err := url.Parse(rawurl)
if err != nil {
continue
}
assert.False(t, IsRedirectAllowed(u, []string{"example.com"}), "for %s expected false",
u.String())
}
}
func TestIsLoopback(t *testing.T) {
tcs := []struct {
rawurl string
value bool
}{
{"http://localhost", true},
{"http://test.localhost.pomerium.io", false},
{"http://127.0.0.1:9999", true},
{"http://127.22.0.1", true},
{"http://[::1]", true},
{"http://[::2]", false},
{"http://example.com", false},
}
for _, tc := range tcs {
u, err := url.Parse(tc.rawurl)
require.NoError(t, err)
assert.Equal(t, tc.value, IsLoopback(u), "for %s expected %v",
u.String(), tc.value)
}
}

View file

@ -708,6 +708,7 @@ type Settings struct {
AutocertMustStaple *bool `protobuf:"varint,58,opt,name=autocert_must_staple,json=autocertMustStaple,proto3,oneof" json:"autocert_must_staple,omitempty"` AutocertMustStaple *bool `protobuf:"varint,58,opt,name=autocert_must_staple,json=autocertMustStaple,proto3,oneof" json:"autocert_must_staple,omitempty"`
AutocertDir *string `protobuf:"bytes,59,opt,name=autocert_dir,json=autocertDir,proto3,oneof" json:"autocert_dir,omitempty"` AutocertDir *string `protobuf:"bytes,59,opt,name=autocert_dir,json=autocertDir,proto3,oneof" json:"autocert_dir,omitempty"`
SkipXffAppend *bool `protobuf:"varint,61,opt,name=skip_xff_append,json=skipXffAppend,proto3,oneof" json:"skip_xff_append,omitempty"` SkipXffAppend *bool `protobuf:"varint,61,opt,name=skip_xff_append,json=skipXffAppend,proto3,oneof" json:"skip_xff_append,omitempty"`
ProgrammaticRedirectDomainWhitelist []string `protobuf:"bytes,68,rep,name=programmatic_redirect_domain_whitelist,json=programmaticRedirectDomainWhitelist,proto3" json:"programmatic_redirect_domain_whitelist,omitempty"`
} }
func (x *Settings) Reset() { func (x *Settings) Reset() {
@ -1155,6 +1156,13 @@ func (x *Settings) GetSkipXffAppend() bool {
return false return false
} }
func (x *Settings) GetProgrammaticRedirectDomainWhitelist() []string {
if x != nil {
return x.ProgrammaticRedirectDomainWhitelist
}
return nil
}
type Settings_Certificate struct { type Settings_Certificate struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1425,7 +1433,7 @@ var file_config_proto_rawDesc = []byte{
0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe5, 0x24, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xba, 0x25, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28,
0x08, 0x48, 0x00, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x08, 0x48, 0x00, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a,
0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
@ -1633,97 +1641,102 @@ var file_config_proto_rawDesc = []byte{
0x69, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66, 0x69, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66,
0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x08, 0x48, 0x34, 0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x08, 0x48, 0x34,
0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x88, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x88,
0x01, 0x01, 0x1a, 0x81, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x01, 0x01, 0x12, 0x53, 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74,
0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x69, 0x63, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x69, 0x6e, 0x5f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x44, 0x20, 0x03,
0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x28, 0x09, 0x52, 0x23, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63,
0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x57, 0x68,
0x72, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x1a, 0x81, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74,
0x63, 0x65, 0x72, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74,
0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65,
0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x1d, 0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x65, 0x72, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
0x75, 0x67, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x0c, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52,
0x42, 0x12, 0x0a, 0x10, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x65, 0x76, 0x65, 0x6c, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x63, 0x65, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x08, 0x0a,
0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x67, 0x5f,
0x76, 0x65, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f,
0x75, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x73, 0x68,
0x74, 0x70, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f,
0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64,
0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x72, 0x65, 0x73, 0x73, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72,
0x69, 0x74, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x6e, 0x73,
0x69, 0x64, 0x6c, 0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x42, 0x15,
0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d,
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x61, 0x75,
0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x64, 0x6f, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65,
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65,
0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x42, 0x10, 0x0a, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65,
0x0e, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b,
0x14, 0x0a, 0x12, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f,
0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6f, 0x6e, 0x6c, 0x79,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x69,
0x69, 0x64, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x72, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x75, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69,
0x65, 0x73, 0x68, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x72, 0x65, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f,
0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x61, 0x75, 0x74, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x69, 0x64, 0x70,
0x72, 0x6c, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x69,
0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x70, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63,
0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42, 0x18, 0x0a,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x16, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x72, 0x69, 0x74, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x69, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x73, 0x69, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
0x74, 0x68, 0x6d, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42,
0x63, 0x6f, 0x6f, 0x6c, 0x64, 0x6f, 0x77, 0x6e, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65, 0x66, 0x1d, 0x0a, 0x1b, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x74, 0x69, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0e,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x0a, 0x0c, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x18,
0x73, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74, 0x72, 0x0a, 0x16, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61,
0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x16, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x65, 0x66,
0x0a, 0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x63, 0x6f, 0x6f, 0x6c, 0x64, 0x6f, 0x77, 0x6e, 0x42, 0x1b, 0x0a,
0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x19, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65,
0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x61, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6d,
0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x13,
0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x0a, 0x11, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x1a, 0x64, 0x65, 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f,
0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x7a, 0x69, 0x70, 0x6b, 0x69, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x24, 0x0a, 0x22, 0x5f,
0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x67, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x63,
0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x67, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61,
0x11, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f,
0x72, 0x6c, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x69, 0x6e, 0x74, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f,
0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x7a, 0x69, 0x70, 0x6b, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42,
0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x0f, 0x0a, 0x0d, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x39, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75,
0x0a, 0x37, 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x61,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x64, 0x61, 0x74, 0x61,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75,
0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x75, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66,
0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x42, 0x69, 0x6c, 0x65, 0x42, 0x39, 0x0a, 0x37, 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63,
0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75, 0x73, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f,
0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x75, 0x74, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x6b, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0b,
0x69, 0x70, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x42, 0x2e, 0x5a, 0x0a, 0x09, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x42, 0x17, 0x0a, 0x15, 0x5f,
0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61,
0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x69, 0x6e, 0x67, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x74, 0x5f, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x42, 0x0f, 0x0a,
0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0d, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x42, 0x12,
0x0a, 0x10, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x61, 0x70, 0x70, 0x65,
0x6e, 0x64, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69,
0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View file

@ -163,4 +163,5 @@ message Settings {
optional bool autocert_must_staple = 58; optional bool autocert_must_staple = 58;
optional string autocert_dir = 59; optional string autocert_dir = 59;
optional bool skip_xff_append = 61; optional bool skip_xff_append = 61;
repeated string programmatic_redirect_domain_whitelist = 68;
} }

View file

@ -148,6 +148,11 @@ func (p *Proxy) ProgrammaticLogin(w http.ResponseWriter, r *http.Request) error
if err != nil { if err != nil {
return httputil.NewError(http.StatusBadRequest, err) return httputil.NewError(http.StatusBadRequest, err)
} }
if !urlutil.IsRedirectAllowed(redirectURI, state.programmaticRedirectDomainWhitelist) {
return httputil.NewError(http.StatusBadRequest, errors.New("invalid redirect uri"))
}
signinURL := *state.authenticateSigninURL signinURL := *state.authenticateSigninURL
callbackURI := urlutil.GetAbsoluteURL(r) callbackURI := urlutil.GetAbsoluteURL(r)
callbackURI.Path = dashboardPath + "/callback/" callbackURI.Path = dashboardPath + "/callback/"

View file

@ -305,11 +305,48 @@ func TestProxy_ProgrammaticLogin(t *testing.T) {
wantStatus int wantStatus int
wantBody string wantBody string
}{ }{
{"good body not checked", opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, map[string]string{urlutil.QueryRedirectURI: "http://localhost"}, http.StatusOK, ""}, {
{"good body not checked", opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, map[string]string{urlutil.QueryRedirectURI: "http://localhost"}, http.StatusOK, ""}, "good body not checked",
{"router miss, bad redirect_uri query", opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, map[string]string{"bad_redirect_uri": "http://localhost"}, http.StatusNotFound, ""}, opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
{"bad redirect_uri missing scheme", opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, map[string]string{urlutil.QueryRedirectURI: "localhost"}, http.StatusBadRequest, "{\"Status\":400,\"Error\":\"Bad Request: localhost url does contain a valid scheme\"}\n"}, map[string]string{urlutil.QueryRedirectURI: "http://localhost"},
{"bad http method", opts, http.MethodPost, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, map[string]string{urlutil.QueryRedirectURI: "http://localhost"}, http.StatusMethodNotAllowed, ""}, http.StatusOK,
"",
},
{
"good body not checked",
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "http://localhost"},
http.StatusOK,
"",
},
{
"router miss, bad redirect_uri query",
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{"bad_redirect_uri": "http://localhost"},
http.StatusNotFound,
"",
},
{
"bad redirect_uri missing scheme",
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "localhost"},
http.StatusBadRequest,
"{\"Status\":400,\"Error\":\"Bad Request: localhost url does contain a valid scheme\"}\n",
},
{
"bad redirect_uri not whitelisted",
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "https://example.com"},
http.StatusBadRequest,
"{\"Status\":400,\"Error\":\"Bad Request: invalid redirect uri\"}\n",
},
{
"bad http method",
opts, http.MethodPost, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "http://localhost"},
http.StatusMethodNotAllowed,
"",
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -28,12 +28,13 @@ type proxyState struct {
authenticateSigninURL *url.URL authenticateSigninURL *url.URL
authenticateRefreshURL *url.URL authenticateRefreshURL *url.URL
encoder encoding.MarshalUnmarshaler encoder encoding.MarshalUnmarshaler
cookieSecret []byte cookieSecret []byte
refreshCooldown time.Duration refreshCooldown time.Duration
sessionStore sessions.SessionStore sessionStore sessions.SessionStore
sessionLoaders []sessions.SessionLoader sessionLoaders []sessions.SessionLoader
jwtClaimHeaders []string jwtClaimHeaders []string
programmaticRedirectDomainWhitelist []string
} }
func newProxyStateFromConfig(cfg *config.Config) (*proxyState, error) { func newProxyStateFromConfig(cfg *config.Config) (*proxyState, error) {
@ -79,6 +80,7 @@ func newProxyStateFromConfig(cfg *config.Config) (*proxyState, error) {
header.NewStore(state.encoder, httputil.AuthorizationTypePomerium), header.NewStore(state.encoder, httputil.AuthorizationTypePomerium),
queryparam.NewStore(state.encoder, "pomerium_session"), queryparam.NewStore(state.encoder, "pomerium_session"),
} }
state.programmaticRedirectDomainWhitelist = cfg.Options.ProgrammaticRedirectDomainWhitelist
return state, nil return state, nil
} }