remove forward auth (#3628)

This commit is contained in:
Caleb Doxsey 2022-11-23 15:59:28 -07:00 committed by GitHub
parent ba07afc245
commit fa26587f19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 302 additions and 5072 deletions

View file

@ -1,33 +0,0 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.137.0/containers/go/.devcontainer/base.Dockerfile
FROM mcr.microsoft.com/vscode/devcontainers/go:0-1@sha256:ec4067ba197ea0c44268641bd252c0bdfa61228202cee5f447925f9ac76d59b3
# [Optional] Install a version of Node.js using nvm for front end dev
ARG INSTALL_NODE="true"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# install envoy
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
RUN curl -sL 'https://getenvoy.io/gpg' | sudo apt-key add -
RUN add-apt-repository \
"deb [arch=amd64] https://dl.bintray.com/tetrate/getenvoy-deb \
$(lsb_release -cs) \
stable"
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends getenvoy-envoy
# [Optional] Uncomment the next line to use go get to install anything else you need
# RUN go get -x <your-dependency-or-tool>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

View file

@ -1,21 +0,0 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.137.0/containers/go
{
"name": "pomerium-remote-containers",
"runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"go.useGoProxyToCheckForToolUpdates": false,
"go.gopath": "/go",
"go.useLanguageServer": true
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["golang.Go"],
"postCreateCommand": "go version",
"dockerComposeFile": ["envs/nginx.yaml"],
// "dockerComposeFile": ["envs/traefik.yaml"],
"service": "pomerium",
"shutdownAction": "none",
"workspaceFolder": "/workspace"
}

View file

@ -1,32 +0,0 @@
version: "3"
services:
nginx:
image: openresty/openresty
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ../../examples/nginx/verify.conf:/etc/nginx/conf.d/verify.conf
- ../../examples/nginx/pomerium.conf:/etc/nginx/conf.d/pomerium.conf
- ../../examples/nginx/proxy.conf:/etc/nginx/proxy.conf
- ../../examples/nginx/_wildcard.localhost.pomerium.io.pem:/etc/nginx/nginx.pem
- ../../examples/nginx/_wildcard.localhost.pomerium.io-key.pem:/etc/nginx/nginx-key.pem
verify:
image: pomerium/verify
expose:
- 80
pomerium:
build: ../.
volumes:
- ../../:/workspace:cached
command: /bin/sh -c "while sleep 1000; do :; done"
environment:
- INSECURE_SERVER=TRUE
- ADDRESS=:80
- FORWARD_AUTH_URL=https://fwdauth.localhost.pomerium.io
- JWT_CLAIMS_HEADERS="email,groups,user"
expose:
- 80

View file

@ -1,50 +0,0 @@
version: "3"
services:
traefik:
image: traefik:v2.3
command:
- "--accesslog=true"
- "--api.insecure=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.forwardedHeaders.insecure"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker=true"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
verify:
image: pomerium/verify:latest
labels:
- "traefik.http.middlewares.pomerium.forwardauth.authResponseHeaders=X-Pomerium-Claim-Email,X-Pomerium-Claim-User,X-Pomerium-Claim-Groups,X-Pomerium-Jwt-Assertion"
- "traefik.http.middlewares.pomerium.forwardauth.address=http://pomerium/"
- "traefik.http.middlewares.pomerium.forwardauth.trustForwardHeader=true"
- "traefik.http.routers.verify.middlewares=pomerium@docker"
- "traefik.enable=true"
- "traefik.http.routers.verify.rule=Host(`verify.localhost.pomerium.io`)"
- "traefik.http.routers.verify.entrypoints=websecure"
- "traefik.http.routers.verify.tls=true"
pomerium:
build: ../.
volumes:
- ../../:/workspace:cached
command: /bin/sh -c "while sleep 1000; do :; done"
environment:
- INSECURE_SERVER=TRUE
- ADDRESS=:80
- FORWARD_AUTH_URL=http://pomerium
- JWT_CLAIMS_HEADERS="email,groups,user"
labels:
- "traefik.enable=true"
- "traefik.http.routers.pomerium.rule=Host(`authenticate.localhost.pomerium.io`)"
- "traefik.http.routers.pomerium.entrypoints=websecure"
- "traefik.http.routers.pomerium.tls=true"
expose:
- 80

View file

@ -1,21 +0,0 @@
# Remote dev containers
## What
These are configurations for Visual Studio Code telling it how to create or access a development container with a well-defined tool and runtime stack.
Basically, this allows us to run VS Code from within a container, remotely.
## Why
Integrating, testing, and debugging Pomerium behind other fronting proxies (nginx/traefik) in forward-auth configuration is a real pain. In particular, it is difficult to do step debugging inside a containerized environment where part of that environment lives outside the network stack of the other components.
It turns out that bringing the debug environment to the containerized environment is easier than bringing the request flow.
## How
- Install [Remote-container](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
- Change `devcontainer.json` to use the docker compose file you want to test with
- run `Remote-Containers: Rebuild Container` from the Command Palette
- ???
- Debug, code, etc as your normally would.

View file

@ -116,7 +116,7 @@ jobs:
go-version: [1.19.x]
node-version: [16.x]
platform: [ubuntu-latest]
deployment: [kubernetes, multi, nginx, single, traefik]
deployment: [kubernetes, multi, single]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/setup-go@c4a742cab115ed795e34d4513e2cf7d472deb55f

View file

@ -201,11 +201,6 @@ func (a *Authenticate) SignIn(w http.ResponseWriter, r *http.Request) error {
jwtAudience = append(jwtAudience, callbackURL.Host)
}
// add an additional claim for the forward-auth host, if set
if fwdAuth := r.FormValue(urlutil.QueryForwardAuth); fwdAuth != "" {
jwtAudience = append(jwtAudience, fwdAuth)
}
s, err := a.getSessionFromCtx(ctx)
if err != nil {
state.sessionStore.ClearSession(w, r)

View file

@ -133,7 +133,6 @@ func TestAuthenticate_SignIn(t *testing.T) {
{"good with callback uri set", "https", "corp.example.example", map[string]string{urlutil.QueryCallbackURI: "https://some.example/", urlutil.QueryRedirectURI: "https://dst.some.example/"}, &mstore.Store{Session: &sessions.State{}}, identity.MockProvider{}, &mock.Encoder{}, http.StatusFound},
{"bad callback uri set", "https", "corp.example.example", map[string]string{urlutil.QueryCallbackURI: "^", urlutil.QueryRedirectURI: "https://dst.some.example/"}, &mstore.Store{Session: &sessions.State{}}, identity.MockProvider{}, &mock.Encoder{}, http.StatusBadRequest},
{"good programmatic request", "https", "corp.example.example", map[string]string{urlutil.QueryIsProgrammatic: "true", urlutil.QueryRedirectURI: "https://dst.some.example/"}, &mstore.Store{Session: &sessions.State{}}, identity.MockProvider{}, &mock.Encoder{}, http.StatusFound},
{"good additional audience", "https", "corp.example.example", map[string]string{urlutil.QueryForwardAuth: "x.y.z", urlutil.QueryRedirectURI: "https://dst.some.example/"}, &mstore.Store{Session: &sessions.State{}}, identity.MockProvider{}, &mock.Encoder{}, http.StatusFound},
}
for _, tt := range tests {
tt := tt

View file

@ -32,25 +32,24 @@ func (a *Authorize) handleResult(
in *envoy_service_auth_v3.CheckRequest,
request *evaluator.Request,
result *evaluator.Result,
isForwardAuthVerify bool,
) (*envoy_service_auth_v3.CheckResponse, error) {
// when the user is unauthenticated it means they haven't
// logged in yet, so redirect to authenticate
if result.Allow.Reasons.Has(criteria.ReasonUserUnauthenticated) ||
result.Deny.Reasons.Has(criteria.ReasonUserUnauthenticated) {
return a.requireLoginResponse(ctx, in, request, isForwardAuthVerify)
return a.requireLoginResponse(ctx, in, request)
}
// when the user's device is unauthenticated it means they haven't
// registered a webauthn device yet, so redirect to the webauthn flow
if result.Allow.Reasons.Has(criteria.ReasonDeviceUnauthenticated) ||
result.Deny.Reasons.Has(criteria.ReasonDeviceUnauthenticated) {
return a.requireWebAuthnResponse(ctx, in, request, result, isForwardAuthVerify)
return a.requireWebAuthnResponse(ctx, in, request, result)
}
// if there's a deny, the result is denied using the deny reasons.
if result.Deny.Value {
return a.handleResultDenied(ctx, in, request, result, isForwardAuthVerify, result.Deny.Reasons)
return a.handleResultDenied(ctx, in, request, result, result.Deny.Reasons)
}
// if there's an allow, the result is allowed.
@ -59,7 +58,7 @@ func (a *Authorize) handleResult(
}
// otherwise, the result is denied using the allow reasons.
return a.handleResultDenied(ctx, in, request, result, isForwardAuthVerify, result.Allow.Reasons)
return a.handleResultDenied(ctx, in, request, result, result.Allow.Reasons)
}
func (a *Authorize) handleResultAllowed(
@ -75,7 +74,6 @@ func (a *Authorize) handleResultDenied(
in *envoy_service_auth_v3.CheckRequest,
request *evaluator.Request,
result *evaluator.Result,
isForwardAuthVerify bool,
reasons criteria.Reasons,
) (*envoy_service_auth_v3.CheckResponse, error) {
denyStatusCode := int32(http.StatusForbidden)
@ -83,7 +81,7 @@ func (a *Authorize) handleResultDenied(
switch {
case reasons.Has(criteria.ReasonDeviceUnauthenticated):
return a.requireWebAuthnResponse(ctx, in, request, result, isForwardAuthVerify)
return a.requireWebAuthnResponse(ctx, in, request, result)
case reasons.Has(criteria.ReasonDeviceUnauthorized):
denyStatusCode = httputil.StatusDeviceUnauthorized
denyStatusText = httputil.DetailsText(httputil.StatusDeviceUnauthorized)
@ -122,42 +120,36 @@ func (a *Authorize) deniedResponse(
in *envoy_service_auth_v3.CheckRequest,
code int32, reason string, headers map[string]string,
) (*envoy_service_auth_v3.CheckResponse, error) {
respBody := []byte(reason)
respHeader := []*envoy_config_core_v3.HeaderValueOption{}
forwardAuthURL, _ := a.currentOptions.Load().GetForwardAuthURL()
if forwardAuthURL == nil {
// create a http response writer recorder
w := httptest.NewRecorder()
r := getHTTPRequestFromCheckRequest(in)
// create a http response writer recorder
w := httptest.NewRecorder()
r := getHTTPRequestFromCheckRequest(in)
// build the user info / debug endpoint
debugEndpoint, _ := a.userInfoEndpointURL(in) // if there's an error, we just wont display it
// build the user info / debug endpoint
debugEndpoint, _ := a.userInfoEndpointURL(in) // if there's an error, we just wont display it
// run the request through our go error handler
httpErr := httputil.HTTPError{
Status: int(code),
Err: errors.New(reason),
DebugURL: debugEndpoint,
RequestID: requestid.FromContext(ctx),
BrandingOptions: a.currentOptions.Load().BrandingOptions,
}
httpErr.ErrorResponse(ctx, w, r)
// transpose the go http response writer into a envoy response
resp := w.Result()
defer resp.Body.Close()
var err error
respBody, err = io.ReadAll(resp.Body)
if err != nil {
log.Error(ctx).Err(err).Msg("error executing error template")
return nil, err
}
// convert go headers to envoy headers
respHeader = append(respHeader, toEnvoyHeaders(resp.Header)...)
} else {
respHeader = append(respHeader, mkHeader("Content-Type", "text/plain", false))
// run the request through our go error handler
httpErr := httputil.HTTPError{
Status: int(code),
Err: errors.New(reason),
DebugURL: debugEndpoint,
RequestID: requestid.FromContext(ctx),
BrandingOptions: a.currentOptions.Load().BrandingOptions,
}
httpErr.ErrorResponse(ctx, w, r)
// transpose the go http response writer into a envoy response
resp := w.Result()
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error(ctx).Err(err).Msg("error executing error template")
return nil, err
}
// convert go headers to envoy headers
respHeader = append(respHeader, toEnvoyHeaders(resp.Header)...)
// add any additional headers
for k, v := range headers {
@ -182,7 +174,6 @@ func (a *Authorize) requireLoginResponse(
ctx context.Context,
in *envoy_service_auth_v3.CheckRequest,
request *evaluator.Request,
isForwardAuthVerify bool,
) (*envoy_service_auth_v3.CheckResponse, error) {
opts := a.currentOptions.Load()
state := a.state.Load()
@ -191,7 +182,7 @@ func (a *Authorize) requireLoginResponse(
return nil, err
}
if !a.shouldRedirect(in) || isForwardAuthVerify {
if !a.shouldRedirect(in) {
return a.deniedResponse(ctx, in, http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized), nil)
}
@ -223,7 +214,6 @@ func (a *Authorize) requireWebAuthnResponse(
in *envoy_service_auth_v3.CheckRequest,
request *evaluator.Request,
result *evaluator.Result,
isForwardAuthVerify bool,
) (*envoy_service_auth_v3.CheckResponse, error) {
opts := a.currentOptions.Load()
state := a.state.Load()
@ -232,7 +222,7 @@ func (a *Authorize) requireWebAuthnResponse(
return nil, err
}
if !a.shouldRedirect(in) || isForwardAuthVerify {
if !a.shouldRedirect(in) {
return a.deniedResponse(ctx, in, http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized), nil)
}

View file

@ -37,8 +37,7 @@ func TestAuthorize_handleResult(t *testing.T) {
&evaluator.Request{},
&evaluator.Result{
Allow: evaluator.NewRuleResult(false, criteria.ReasonUserUnauthenticated),
},
false)
})
assert.NoError(t, err)
assert.Equal(t, 302, int(res.GetDeniedResponse().GetStatus().GetCode()))
@ -47,8 +46,7 @@ func TestAuthorize_handleResult(t *testing.T) {
&evaluator.Request{},
&evaluator.Result{
Deny: evaluator.NewRuleResult(false, criteria.ReasonUserUnauthenticated),
},
false)
})
assert.NoError(t, err)
assert.Equal(t, 302, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
@ -191,8 +189,7 @@ func TestRequireLogin(t *testing.T) {
t.Run("accept empty", func(t *testing.T) {
res, err := a.requireLoginResponse(context.Background(),
&envoy_service_auth_v3.CheckRequest{},
&evaluator.Request{},
false)
&evaluator.Request{})
require.NoError(t, err)
assert.Equal(t, http.StatusFound, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
@ -209,8 +206,7 @@ func TestRequireLogin(t *testing.T) {
},
},
},
&evaluator.Request{},
false)
&evaluator.Request{})
require.NoError(t, err)
assert.Equal(t, http.StatusFound, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
@ -227,8 +223,7 @@ func TestRequireLogin(t *testing.T) {
},
},
},
&evaluator.Request{},
false)
&evaluator.Request{})
require.NoError(t, err)
assert.Equal(t, http.StatusUnauthorized, int(res.GetDeniedResponse().GetStatus().GetCode()))
})

View file

@ -43,18 +43,6 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
hreq := getHTTPRequestFromCheckRequest(in)
ctx = requestid.WithValue(ctx, requestid.FromHTTPHeader(hreq.Header))
isForwardAuth := a.isForwardAuth(in)
if isForwardAuth {
// update the incoming http request's uri to match the forwarded URI
fwdAuthURI := urlutil.GetForwardAuthURL(hreq)
in.Attributes.Request.Http.Scheme = fwdAuthURI.Scheme
in.Attributes.Request.Http.Host = fwdAuthURI.Host
in.Attributes.Request.Http.Path = fwdAuthURI.EscapedPath()
if fwdAuthURI.RawQuery != "" {
in.Attributes.Request.Http.Path += "?" + fwdAuthURI.RawQuery
}
}
sessionState, _ := state.sessionStore.LoadSessionState(hreq)
var s sessionOrServiceAccount
@ -93,22 +81,7 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
ctx = contextutil.WithPolicyEvaluationTraces(ctx, res.Traces)
}
isForwardAuthVerify := isForwardAuth && hreq.URL.Path == "/verify"
return a.handleResult(ctx, in, req, res, isForwardAuthVerify)
}
// isForwardAuth returns if the current request is a forward auth route.
func (a *Authorize) isForwardAuth(req *envoy_service_auth_v3.CheckRequest) bool {
opts := a.currentOptions.Load()
forwardAuthURL, err := opts.GetForwardAuthURL()
if err != nil || forwardAuthURL == nil {
return false
}
checkURL := getCheckRequestURL(req)
return urlutil.StripPort(checkURL.Host) == urlutil.StripPort(forwardAuthURL.Host)
return a.handleResult(ctx, in, req, res)
}
func (a *Authorize) getEvaluatorRequestFromCheckRequest(

View file

@ -6,17 +6,13 @@ import (
"testing"
envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"github.com/pomerium/pomerium/authorize/evaluator"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/atomicutil"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/sessions"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
)
@ -102,161 +98,6 @@ func Test_getEvaluatorRequest(t *testing.T) {
assert.Equal(t, expect, actual)
}
func Test_handleForwardAuth(t *testing.T) {
tests := []struct {
name string
checkReq *envoy_service_auth_v3.CheckRequest
forwardAuthURL string
want bool
}{
{
name: "enabled",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri=" + url.QueryEscape("https://example.com/some/path?qs=1"),
Host: "forward-auth.example.com",
Scheme: "https",
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: true,
},
{
name: "disabled",
checkReq: nil,
forwardAuthURL: "",
want: false,
},
{
name: "honor x-forwarded-uri set",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/",
Host: "forward-auth.example.com",
Scheme: "https",
Headers: map[string]string{
httputil.HeaderForwardedURI: "/foo/bar",
httputil.HeaderForwardedProto: "https",
httputil.HeaderForwardedHost: "example.com",
},
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: true,
},
{
name: "request with invalid forward auth url",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri=" + url.QueryEscape("https://example.com?q=foo"),
Host: "fake-forward-auth.example.com",
Scheme: "https",
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: false,
},
{
name: "request with invalid path",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/foo?uri=" + url.QueryEscape("https://example.com?q=foo"),
Host: "forward-auth.example.com",
Scheme: "https",
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: true,
},
{
name: "request with empty uri",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri=",
Host: "forward-auth.example.com",
Scheme: "https",
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: true,
},
{
name: "request with invalid uri",
checkReq: &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri= http://example.com/foo",
Host: "forward-auth.example.com",
Scheme: "https",
},
},
},
},
forwardAuthURL: "https://forward-auth.example.com",
want: true,
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
a := &Authorize{currentOptions: config.NewAtomicOptions(), state: atomicutil.NewValue(new(authorizeState))}
a.currentOptions.Store(&config.Options{ForwardAuthURLString: tc.forwardAuthURL})
got := a.isForwardAuth(tc.checkReq)
if diff := cmp.Diff(got, tc.want); diff != "" {
t.Errorf("Authorize.Check() = %s", diff)
}
})
}
}
func Test_getEvaluatorRequestWithPortInHostHeader(t *testing.T) {
a := &Authorize{currentOptions: config.NewAtomicOptions(), state: atomicutil.NewValue(new(authorizeState))}
a.currentOptions.Store(&config.Options{
@ -322,100 +163,6 @@ func (m mockDataBrokerServiceClient) Put(ctx context.Context, in *databroker.Put
return m.put(ctx, in, opts...)
}
func TestAuthorize_Check(t *testing.T) {
opt := config.NewDefaultOptions()
opt.AuthenticateURLString = "https://authenticate.example.com"
opt.DataBrokerURLString = "https://databroker.example.com"
opt.SharedKey = "E8wWIMnihUx+AUfRegAQDNs8eRb3UrB5G3zlJW9XJDM="
a, err := New(&config.Config{Options: opt})
if err != nil {
t.Fatal(err)
}
a.currentOptions.Store(&config.Options{ForwardAuthURLString: "https://forward-auth.example.com"})
cmpOpts := []cmp.Option{
cmpopts.IgnoreUnexported(envoy_service_auth_v3.CheckResponse{}),
cmpopts.IgnoreUnexported(status.Status{}),
cmpopts.IgnoreTypes(envoy_service_auth_v3.DeniedHttpResponse{}),
}
tests := []struct {
name string
in *envoy_service_auth_v3.CheckRequest
want *envoy_service_auth_v3.CheckResponse
wantErr bool
}{
{
"basic deny",
&envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Id: "id-1234",
Method: "GET",
Headers: map[string]string{
"accept": "application/json",
"x-forwarded-proto": "https",
},
Path: "/some/path?qs=1",
Host: "example.com",
Scheme: "http",
Body: "BODY",
},
},
},
},
&envoy_service_auth_v3.CheckResponse{
Status: &status.Status{Code: 7, Message: "Access Denied"},
HttpResponse: &envoy_service_auth_v3.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v3.DeniedHttpResponse{},
},
},
false,
},
{
"basic forward-auth deny",
&envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Source: &envoy_service_auth_v3.AttributeContext_Peer{
Certificate: url.QueryEscape(certPEM),
},
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri=" + url.QueryEscape("https://example.com/some/path?qs=1"),
Host: "forward-auth.example.com",
Scheme: "https",
},
},
},
},
&envoy_service_auth_v3.CheckResponse{
Status: &status.Status{Code: 7, Message: "Access Denied"},
HttpResponse: &envoy_service_auth_v3.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v3.DeniedHttpResponse{},
},
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := a.Check(context.TODO(), tt.in)
if (err != nil) != tt.wantErr {
t.Errorf("Authorize.Check() error = %v, wantErr %v", err, tt.wantErr)
return
}
if diff := cmp.Diff(got, tt.want, cmpOpts...); diff != "" {
t.Errorf("NewStore() = %s", diff)
}
})
}
}
func mustParseURL(rawURL string) url.URL {
u, err := url.Parse(rawURL)
if err != nil {

View file

@ -84,86 +84,9 @@ func (b *Builder) buildPomeriumHTTPRoutes(options *config.Options, domain string
b.buildControlPlanePathRoute("/", false),
)
}
// if we're the proxy and this is the forward-auth url
forwardAuthURL, err := options.GetForwardAuthURL()
if err != nil {
return nil, err
}
if config.IsProxy(options.Services) && hostMatchesDomain(forwardAuthURL, domain) {
// disable ext_authz and pass request to proxy handlers that enable authN flow
r, err := b.buildControlPlanePathAndQueryRoute("/verify", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI})
if err != nil {
return nil, err
}
routes = append(routes, r)
r, err = b.buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI})
if err != nil {
return nil, err
}
routes = append(routes, r)
r, err = b.buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI})
if err != nil {
return nil, err
}
routes = append(routes, r)
// otherwise, enforce ext_authz; pass all other requests through to an upstream
// handler that will simply respond with http status 200 / OK indicating that
// the fronting forward-auth proxy can continue.
r, err = b.buildControlPlaneProtectedPrefixRoute("/")
if err != nil {
return nil, err
}
routes = append(routes, r)
}
return routes, nil
}
func (b *Builder) buildControlPlaneProtectedPrefixRoute(prefix string) (*envoy_config_route_v3.Route, error) {
return &envoy_config_route_v3.Route{
Name: "pomerium-protected-prefix-" + prefix,
Match: &envoy_config_route_v3.RouteMatch{
PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{Prefix: prefix},
},
Action: &envoy_config_route_v3.Route_Route{
Route: &envoy_config_route_v3.RouteAction{
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
Cluster: httpCluster,
},
},
},
}, nil
}
func (b *Builder) buildControlPlanePathAndQueryRoute(path string, queryparams []string) (*envoy_config_route_v3.Route, error) {
var queryParameterMatchers []*envoy_config_route_v3.QueryParameterMatcher
for _, q := range queryparams {
queryParameterMatchers = append(queryParameterMatchers,
&envoy_config_route_v3.QueryParameterMatcher{
Name: q,
QueryParameterMatchSpecifier: &envoy_config_route_v3.QueryParameterMatcher_PresentMatch{PresentMatch: true},
})
}
return &envoy_config_route_v3.Route{
Name: "pomerium-path-and-query" + path,
Match: &envoy_config_route_v3.RouteMatch{
PathSpecifier: &envoy_config_route_v3.RouteMatch_Path{Path: path},
QueryParameters: queryParameterMatchers,
},
Action: &envoy_config_route_v3.Route_Route{
Route: &envoy_config_route_v3.RouteAction{
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
Cluster: httpCluster,
},
},
},
TypedPerFilterConfig: map[string]*any.Any{
"envoy.filters.http.ext_authz": disableExtAuthz,
},
}, nil
}
func (b *Builder) buildControlPlanePathRoute(path string, protected bool) *envoy_config_route_v3.Route {
r := &envoy_config_route_v3.Route{
Name: "pomerium-path-" + path,

View file

@ -82,7 +82,6 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
Services: "all",
AuthenticateURLString: "https://authenticate.example.com",
AuthenticateCallbackPath: "/oauth2/callback",
ForwardAuthURLString: "https://forward-auth.example.com",
}
routes, err := b.buildPomeriumHTTPRoutes(options, "authenticate.example.com")
require.NoError(t, err)
@ -116,7 +115,6 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
Services: "all",
AuthenticateURLString: "https://authenticate.example.com",
AuthenticateCallbackPath: "/oauth2/callback",
ForwardAuthURLString: "https://forward-auth.example.com",
Policies: []config.Policy{{
From: "https://from.example.com",
To: mustParseWeightedURLs(t, "https://to.example.com"),
@ -143,7 +141,6 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
Services: "all",
AuthenticateURLString: "https://authenticate.example.com",
AuthenticateCallbackPath: "/oauth2/callback",
ForwardAuthURLString: "https://forward-auth.example.com",
Policies: []config.Policy{{
From: "https://from.example.com",
To: mustParseWeightedURLs(t, "https://to.example.com"),

View file

@ -222,14 +222,6 @@ type Options struct {
GRPCClientTimeout time.Duration `mapstructure:"grpc_client_timeout" yaml:"grpc_client_timeout,omitempty"`
GRPCClientDNSRoundRobin bool `mapstructure:"grpc_client_dns_roundrobin" yaml:"grpc_client_dns_roundrobin,omitempty"`
// ForwardAuthEndpoint allows for a given route to be used as a forward-auth
// endpoint instead of a reverse proxy. Some third-party proxies that do not
// have rich access control capabilities (nginx, envoy, ambassador, traefik)
// allow you to delegate and authenticate each request to your website
// with an external server or service. Pomerium can be configured to accept
// these requests with this switch
ForwardAuthURLString string `mapstructure:"forward_auth_url" yaml:"forward_auth_url,omitempty"`
// DataBrokerURLString is the routable destination of the databroker service's gRPC endpoint.
DataBrokerURLString string `mapstructure:"databroker_service_url" yaml:"databroker_service_url,omitempty"`
DataBrokerURLStrings []string `mapstructure:"databroker_service_urls" yaml:"databroker_service_urls,omitempty"`
@ -602,13 +594,6 @@ func (o *Options) Validate() error {
}
}
if o.ForwardAuthURLString != "" {
_, err := urlutil.ParseAndValidateURL(o.ForwardAuthURLString)
if err != nil {
return fmt.Errorf("config: bad forward-auth-url %s : %w", o.ForwardAuthURLString, err)
}
}
if o.PolicyFile != "" {
return errors.New("config: policy file setting is deprecated")
}
@ -823,15 +808,6 @@ func (o *Options) getURLs(strs ...string) ([]*url.URL, error) {
return urls, nil
}
// GetForwardAuthURL returns the ForwardAuthURL.
func (o *Options) GetForwardAuthURL() (*url.URL, error) {
rawurl := o.ForwardAuthURLString
if rawurl == "" {
return nil, nil
}
return urlutil.ParseAndValidateURL(rawurl)
}
// GetGRPCAddr gets the gRPC address.
func (o *Options) GetGRPCAddr() string {
// to avoid port collision when running on localhost
@ -1114,11 +1090,6 @@ func (o *Options) GetAllRouteableHTTPDomains() ([]string, error) {
// GetAllRouteableHTTPDomainsForTLSServerName returns all the possible HTTP domains handled by the Pomerium options
// for the given TLS server name.
func (o *Options) GetAllRouteableHTTPDomainsForTLSServerName(tlsServerName string) ([]string, error) {
forwardAuthURL, err := o.GetForwardAuthURL()
if err != nil {
return nil, err
}
domains := sets.NewSorted[string]()
if IsAuthenticate(o.Services) {
authenticateURL, err := o.GetInternalAuthenticateURL()
@ -1162,13 +1133,6 @@ func (o *Options) GetAllRouteableHTTPDomainsForTLSServerName(tlsServerName strin
}
}
}
if forwardAuthURL != nil {
for _, h := range urlutil.GetDomainsForURL(*forwardAuthURL) {
if tlsServerName == "" || urlutil.StripPort(h) == tlsServerName {
domains.Add(h)
}
}
}
}
return domains.ToSlice(), nil
@ -1457,9 +1421,6 @@ func (o *Options) ApplySettings(ctx context.Context, settings *config.Settings)
if settings.GrpcInsecure != nil {
o.GRPCInsecure = settings.GetGrpcInsecure()
}
if settings.ForwardAuthUrl != nil {
o.ForwardAuthURLString = settings.GetForwardAuthUrl()
}
if len(settings.DatabrokerServiceUrls) > 0 {
o.DataBrokerURLStrings = settings.GetDatabrokerServiceUrls()
}

View file

@ -361,8 +361,6 @@ func Test_NewOptionsFromConfigEnvVar(t *testing.T) {
{"no certs no insecure mode set", map[string]string{"SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, false},
{"good disable headers ", map[string]string{"HEADERS": "disable:true", "INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, false},
{"bad whitespace in secret", map[string]string{"INSECURE_SERVER": "true", "SERVICES": "authenticate", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM=\n"}, true},
{"good forward auth url", map[string]string{"FORWARD_AUTH_URL": "https://databroker.example", "INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, false},
{"bad forward auth url", map[string]string{"FORWARD_AUTH_URL": "databroker.example", "INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, true},
{"same addr and grpc addr", map[string]string{"SERVICES": "databroker", "ADDRESS": "0", "GRPC_ADDRESS": "0", "INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, false},
{"bad cert files", map[string]string{"INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM=", "CERTIFICATES": "./test-data/example-cert.pem"}, true},
{"good cert file", map[string]string{"CERTIFICATE_FILE": "./testdata/example-cert.pem", "CERTIFICATE_KEY_FILE": "./testdata/example-key.pem", "INSECURE_SERVER": "true", "SHARED_SECRET": "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="}, false},
@ -631,7 +629,6 @@ func TestOptions_DefaultURL(t *testing.T) {
AuthenticateURLString: "https://authenticate.example.com",
AuthorizeURLString: "https://authorize.example.com",
DataBrokerURLString: "https://databroker.example.com",
ForwardAuthURLString: "https://forwardauth.example.com",
}
tests := []struct {
name string
@ -641,11 +638,9 @@ func TestOptions_DefaultURL(t *testing.T) {
{"default authenticate url", defaultOptions.GetAuthenticateURL, "https://127.0.0.1"},
{"default authorize url", defaultOptions.GetAuthenticateURL, "https://127.0.0.1"},
{"default databroker url", defaultOptions.GetAuthenticateURL, "https://127.0.0.1"},
{"default forward auth url", defaultOptions.GetAuthenticateURL, "https://127.0.0.1"},
{"good authenticate url", opts.GetAuthenticateURL, "https://authenticate.example.com"},
{"good authorize url", firstURL(opts.GetAuthorizeURLs), "https://authorize.example.com"},
{"good databroker url", firstURL(opts.GetDataBrokerURLs), "https://databroker.example.com"},
{"good forward auth url", opts.GetForwardAuthURL, "https://forwardauth.example.com"},
}
for _, tc := range tests {

View file

@ -1,104 +0,0 @@
version: "3"
services:
nginx:
image: pomerium/nginx-proxy:latest
ports:
- "443:443"
volumes:
# NOTE!!! : nginx must be supplied with your wildcard certificates.
# see : https://github.com/jwilder/nginx-proxy#wildcard-certificates
- ~/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer:/etc/nginx/certs/corp.beyondperimeter.com.crt:ro
- ~/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key:/etc/nginx/certs/corp.beyondperimeter.com.key:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
pomerium-authenticate:
image: pomerium/pomerium:latest # or `build: .` to build from source
restart: always
environment:
- SERVICES=authenticate
- INSECURE_SERVER=TRUE
# NOTE!: Replace with your identity provider settings https://www.pomerium.com/docs/identity-providers.html
# - IDP_PROVIDER=okta
# - IDP_PROVIDER_URL=https://beyondperimeter.okta.com
# - IDP_CLIENT_ID=REPLACE_ME
# - IDP_CLIENT_SECRET=REPLACE_ME
# NOTE! Generate new secret keys! e.g. `head -c32 /dev/urandom | base64`
# Generated secret keys must match between services
- SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M=
- COOKIE_SECRET=V2JBZk0zWGtsL29UcFUvWjVDWWQ2UHExNXJ0b2VhcDI=
# Tell nginx how to proxy pomerium's routes
- VIRTUAL_PROTO=http
- VIRTUAL_HOST=authenticate.corp.beyondperimeter.com
- VIRTUAL_PORT=443
- DATABROKER_SERVICE_URL=http://pomerium-databroker:443
volumes:
- ../config/config.example.yaml:/pomerium/config.yaml:ro
expose:
- 443
pomerium-proxy:
image: pomerium/pomerium:latest # or `build: .` to build from source
restart: always
environment:
- SERVICES=proxy
- INSECURE_SERVER=TRUE
# IMPORTANT! If you are running pomerium behind another ingress (loadbalancer/firewall/etc)
# you must tell pomerium proxy how to communicate using an internal hostname for RPC
- AUTHORIZE_SERVICE_URL=http://pomerium-authorize:443
# When communicating internally, rPC is going to get a name conflict expecting an external
# facing certificate name (i.e. authenticate-service.local vs *.corp.example.com).
- SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M=
- COOKIE_SECRET=V2JBZk0zWGtsL29UcFUvWjVDWWQ2UHExNXJ0b2VhcDI=
# Tell nginx how to proxy pomerium's routes
- VIRTUAL_PROTO=http
- VIRTUAL_HOST=*.corp.beyondperimeter.com
- VIRTUAL_PORT=443
volumes:
- ../config/config.example.yaml:/pomerium/config.yaml:ro
expose:
- 443
pomerium-authorize:
image: pomerium/pomerium:latest # or `build: .` to build from source
restart: always
environment:
- SERVICES=authorize
- SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M=
- GRPC_INSECURE=TRUE
- GRPC_ADDRESS=:443
volumes:
# Retrieve non-secret config keys from the config file : https://www.pomerium.com/docs/reference/
# See `config.example.yaml` and modify to fit your needs.
- ../config/config.example.yaml:/pomerium/config.yaml:ro
expose:
- 443
pomerium-databroker:
image: pomerium/pomerium:latest # or `build: .` to build from source
restart: always
environment:
- SERVICES=databroker
- SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M=
- GRPC_INSECURE=TRUE
- GRPC_ADDRESS=:443
volumes:
# Retrieve non-secret config keys from the config file : https://www.pomerium.com/docs/reference/
# See `config.example.yaml` and modify to fit your needs.
- ../config/config.example.yaml:/pomerium/config.yaml:ro
expose:
- 443
# https://verify.corp.beyondperimeter.com
verify:
image: pomerium/verify:latest
expose:
- 80
# https://hello.corp.beyondperimeter.com
hello:
image: gcr.io/google-samples/hello-app:1.0
expose:
- 8080

View file

@ -28,8 +28,8 @@ echo "=> install pomerium with helm"
helm install \
pomerium \
pomerium/pomerium \
--set ingress.secret.cert="$(base64 -i $HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer)" \
--set ingress.secret.key="$(base64 -i $HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key)" \
--set ingress.secret.cert="$(base64 -i "$HOME"/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer)" \
--set ingress.secret.key="$(base64 -i "$HOME"/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key)" \
--values docs/configuration/examples/kubernetes/values.yaml
# When done, clean up by deleting the cluster!

View file

@ -1,17 +0,0 @@
# Pomerium as external auth provider for Nginx
Run this demo locally on your docker-compose capable workstation, or replace `localhost.pomerium.io` with your own domain if running on a server.
## Includes
- Authentication and Authorization managed by pomerium
- Routing / reverse proxying handled by nginx
## How
- Update `config.yaml` for your e-mail address, if not using gmail/google.
- Replace secrets in `config.yaml`.
- Run `docker-compose up` from this directory.
- Navigate to `https://verify.localhost.pomerium.io`
- ???
- Profit

View file

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXfeTmeNmQFK3r
CrLcdh9pVrsSjbNOAP2BIQ3AfGdf/S0UqjU1UhXOb2gLm5Dsj/vFvs/fSkiahBdj
7zR1dh7jdOnf3QgcAjIMTo7sJggsABHBF0vHVMXJtNoWmZ+AYOirsn22N3EoUNmX
jlr19LnW07DtkHJFPYsYFy01uOEKGbzKQh8E6DFv3tPNp/raUHkGSAUpT11tZcdf
vbSHuSN4xzGOs6T9QCnu0wCGb2MJNa8l5dhtVuy59jcZWM2i4EBLnXsYbHhkg/uZ
xnVfm3YxgNM8bA2T1DqSUxjpLt7Dty9MHBaEyHVrH/nXYluF1wI7jNC2A7dE6VKq
AkSmFKG7AgMBAAECggEARCYmW9TgSTahAfIyOpKIwJGTO/zgNc0OXuYLKVKuhqbU
uPJTPXemOdD1wKYEISwv3YvIxb8CUwtvMkWV+4fNoPV6eTe3ttPi7A10Ga61auTi
uIQbjQB8RJwTVI5k6P681n/uTdAe0zcueUWl8p7gntX34EmMOeWKtaWuwIylbsG8
Ftvls8dI/soHUBgZT9HHo3ZitaRQtDYN+YjqAWfQCtPFrBJ5TPS9W6z3cmB/2l19
nkwZljomj+mJZseEStQUOH/YXf7jpZCWNuxj9l9C+/F5pmiQX6w87thohVXFPmXx
zEExPHePvThx4CxrUGyBeWfzUaYMfzx1T/gyMixDYQKBgQD642G2ElXQSnlZZoLf
gMYTazAjtv7PIRVcVjOJfUORx5LP4sV7CkWokIMdbzfiVkerWt6kb2HDhBskvdFW
ag6Fl8t/Miyi+ZTrE/PmZJqs7fGtmSqjY8wWKfcN6gyTPkh789DXU7ddJIiJLQ10
sf5Mg2sQkMLQo5XnnauV/SmKiQKBgQDb4eL/MmSR7yKnjxjvek7xXJGqaEXBmazn
pUhp6B+7aHsAg/u71DjzirMn2Ra3+WQ+sDQwbkMQuokqBPUij0Bcv61QSaocjrnb
PmwtXlHeyk9RnGj60oW55gIuJw0EseI17IaqHJPyDNVCQ9WJteI4y8Da+m0E5ohZ
udXzk9DpIwKBgCK3xnS4ktFxDNvXOLMPEdnsEkxO7XHiRR9y+kzDXc9Vi7ZizisZ
n8wUu2AeXOBgSiinOXoNw7yXkl4COm633GyWNd3TJqQi332sVCsErvbRMolwUZss
mzhR9FMjmTvi+YrVkYfKmOw1uwMojd0hKGyUHwO61IqkqIDVq8Hkt5PpAoGBAMlH
RdwF7ToJhdeMjm7pr0oSSuWK/g/y9Ow3yMnpyuJrCe2248FUy61k0gswFjPi/3jD
I4MR7CJsHxNv5lX0fB5q9+P/CtGJdWjVA4GkTZ175I/4dcDk5bT+cBB/ftNFYqWq
Frux3Vw9kxpNrjOZY7RKEAhkJVfPEBHSo5+NODexAoGAXohoO9jOeLtYFOYRdKxj
bbL7fwiR+ecBakiuakoIFc+ibH57fDvxA6YkbLFOVNrpsTVNIbgO9Jois3GhrEGH
8TbGfohpmwC7nZ62aFJSNxD48gYvYzMamo0WymM1uH3jwlJY/kVO6KHopcN8+kQS
/zG8+V/OgnBBvyfWWX8ygio=
-----END PRIVATE KEY-----

View file

@ -1,24 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEAjCCAmqgAwIBAgIRAJGdiQDsLfchZYUtx06mQpswDQYJKoZIhvcNAQELBQAw
RTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMQ0wCwYDVQQLEwR0ZXN0
MRQwEgYDVQQDEwtta2NlcnQgdGVzdDAeFw0xOTA2MDEwMDAwMDBaFw0zMDA4MjQx
OTQyNTBaMDgxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0
ZTENMAsGA1UECxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANd95OZ42ZAUresKstx2H2lWuxKNs04A/YEhDcB8Z1/9LRSqNTVSFc5vaAubkOyP
+8W+z99KSJqEF2PvNHV2HuN06d/dCBwCMgxOjuwmCCwAEcEXS8dUxcm02haZn4Bg
6KuyfbY3cShQ2ZeOWvX0udbTsO2QckU9ixgXLTW44QoZvMpCHwToMW/e082n+tpQ
eQZIBSlPXW1lx1+9tIe5I3jHMY6zpP1AKe7TAIZvYwk1ryXl2G1W7Ln2NxlYzaLg
QEudexhseGSD+5nGdV+bdjGA0zxsDZPUOpJTGOku3sO3L0wcFoTIdWsf+ddiW4XX
AjuM0LYDt0TpUqoCRKYUobsCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU0t8UaNj7
xry1h0qnTAm8Sxv69aMwIgYDVR0RBBswGYIXKi5sb2NhbGhvc3QucG9tZXJpdW0u
aW8wDQYJKoZIhvcNAQELBQADggGBAJhOdplKGoR7/83qDjELdjhaoecZASqs5M+P
Sxm7z5s+KSbElebw6/rHJciKAlT9tqHQO6CqliQ9hl4AHWxi+cjpwfxyqWn/VGIa
4WoGyInd/I2PDne+5bIj0MXkikilk5NsJtypvGGjZJTF2T07QfXLlLi3nYTMHYzt
TLZpu7vK+B2ZGCGG4o9pws5ZFjtuOXEDGsE1APPp3xjvC/uJt2xgqo4XcRGIVHgm
mY2yi5KmUCAv0HHdDjxZoqEDazv8t/VuPc3hJcuUcIBZvyMFyPNMqN5ePI7D5TkD
zOqW28I8jpB5zdDpCr4qXsU+Cf+4fB0jDncBq95n1v8EJsm7zeTIFZNgLv3ISthF
lGEFS1zv+ybCOYPl3H0yd13S6N4QUHbESXHvZ2l2V1qDiKrfFcVhQ5ZEDD7/HDqT
N+v7zzMOzmPNCSiky1lMMj/vP87AjaliJnvBcT4F5iU867ws/Refh+yege2l6roO
LEM1YmdMYuNFbCsS2BbQsK9mbDkcmQ==
-----END CERTIFICATE-----

View file

@ -1,26 +0,0 @@
# Main configuration flags : https://www.pomerium.com/docs/reference/
pomerium_debug: true
address: :80
cookie_secret: YVFTMIfW8yBJw+a6sYwdW8rHbU+IAAV/SUkCTg9Jtpo=
shared_secret: 80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ=
idp_provider: "google"
idp_client_id: REPLACEME
idp_client_secret: REPLACEME
insecure_server: true
forward_auth_url: http://fwdauth.localhost.pomerium.io
authenticate_service_url: https://authenticate.localhost.pomerium.io
routes:
- from: https://verify.localhost.pomerium.io
to: http://verify:8000
policy:
- allow:
or:
- domain:
is: pomerium.com
- domain:
is: gmail.com
pass_identity_headers: true

View file

@ -1,29 +0,0 @@
version: "3"
services:
nginx:
# to emulate nginx-ingress behavior, use openresty which comes with 'escaped_request_uri'
# pre-compiled. Also uncomment lines marked `uncomment to emulate nginx-ingress behavior`
# in the nginx `.conf` configuration files.
# image: openresty/openresty
image: nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./verify.conf:/etc/nginx/conf.d/verify.conf
- ./pomerium.conf:/etc/nginx/conf.d/pomerium.conf
- ./_wildcard.localhost.pomerium.io.pem:/etc/nginx/nginx.pem
- ./_wildcard.localhost.pomerium.io-key.pem:/etc/nginx/nginx-key.pem
- ./proxy.conf:/etc/nginx/proxy.conf
verify:
image: pomerium/verify
expose:
- 8000
pomerium:
image: pomerium/pomerium:latest
volumes:
- ./config.yaml:/pomerium/config.yaml:ro
expose:
- 80

View file

@ -1,18 +0,0 @@
# Pomerium endpoint
server {
listen 443 ssl;
server_name authenticate.localhost.pomerium.io fwdauth.localhost.pomerium.io;
ssl_certificate /etc/nginx/nginx.pem;
ssl_certificate_key /etc/nginx/nginx-key.pem;
location / {
proxy_pass http://pomerium;
include /etc/nginx/proxy.conf;
}
}
# Define an upstream so that we don't need resolvers when we use variables in proxy_pass directives
# https://stackoverflow.com/questions/17685674/nginx-proxy-pass-with-remote-addr
upstream pomerium {
server pomerium;
}

View file

@ -1,64 +0,0 @@
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
# uncomment to emulate nginx-ingress
# set_escape_uri $escaped_request_uri $request_uri;
# proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_redirect off;

View file

@ -1,40 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCub8x6MRI1aWZV
k7qfpQn7CK6fCHNceBhSQFMHBJXQLEAe34uNgF1h+NQGM2zaKDZ8hIsRNZq0dV/g
Xyd7AMA5C8DyyHfqzoiHJeTXKoqGEmi/MyXfnHr6N4rQpoG97SbACKYfNOh/MD05
gIg51LrbTK1GzFyg0AVntsvmm3r3NNHv/BJKVKV+2HZx1D83xcBstdLDAPdtmU3z
STzixQYDTlzs1gUrJPfJAi1sAMM/RbDKTmgsYJopxADRYldOIvZEZqPrupInUi4v
iFEosb0dpSSeHkKBgVl81X2ro+WH4vgfoeGkpu6mh67FfN1WljMf63E6yOEBcqxE
+Vc9O+ysruODnma1d+DfXoHoZInUhzUM7nTdbsftmb0C5bFA3ts16WGZ1g21Hi7m
NH2MdW2hLyRngAU9AHTWObdBxb4MBmBSF5ZIElcsfLABilHG508L2ZYM+uqOb0iW
AMcVyrli7EaDEOF/oUv7WsDAekwGKKfy9exfWhw7+yn+UYG4oPUCAwEAAQKCAYAx
e5d2xjrTGf4koo6bQPcO1kyq4nvPLGZB1ut2ny9caWEbIPD2iAZ1h1+mDqp/TE8A
jZzhmeIz9OPowzVw6CqfRB1NAd86pbIHHJHJE9FN7ST3sCu7PimIl37yZ3mAhiiq
6wks6xZVFjsX98UtGpKTKTIyVkCkgb42yJ0Y4txECiDPwiLyIQb9b6xR6BKy4I8Q
h5etJ7YIyidZr1ntPlTRVUZ5DNFUht0fkVWPQLwiU8Ot8AYPKKwy0t4kh5Aao0Hf
CDQP6Y5/XXKLl5bNi/SO5eg6jk3DnILwPkjXM3tVxcag+KmMc4GfVmVVDP+QkmVl
LtGOHuBeyicdC5/jt6xMwbsEdY/YFjlO4WDH/5e8F7KG1X3OjTmqwdNjSNg4rXni
u0ZEG+/o80ha21lCys+QpQ9PQmYPaGlzVPY9z0F6JsAlXNbNRIIOsJNEKlAICWXF
9YyAaD8pV60UhK67q5wZ3uxyAjplM5+930asL5MPgb4BEvRY4bWlOe55lySXsbUC
gcEA0HnqdCQBfmiylZv4Uh8JVojSZcZFtFU8V02TY/XrWjwzWv8z1ZXnzx18kAz7
islThqlvr38HXwFfUNDhI/IIp+8zcvT9T56e1T8jYxhcaTZBEZ7XlG/jWbWbRx/k
JEctixh7J5EhbsxhC7TfuH9lQ2r50WvmmrGpLoqHDe5fyKFTpbUkrGB19idiw9oI
awjxOgN+uRrTFjuOPhxgfSwJGwPnE0my8lS/5fPvNUuQdWecqEe3CTFjVXY44IzB
7W9HAoHBANYzbsNClt8HgLyp0XZg4W19BuCic6qJZhOSVoUlGFTTa2dTQnSfq5NL
O1GCfZ/fy0QZvvBebf+Mf3WycEv/BbxRT0lDP0QjdamHkn9mGK+ODmYxvPu7Lqk9
5acrXM8uXuK4bkT2eXKE2H7x9jrnxpSI/zE3cwic+GlQWH85ywAKwT07g3BiM5GJ
pHpoJGwxraBUDb6HPTgTsVzPtvCbKqYw9uUalPDGI1Pc0iEitT5s41HT57P10hnD
gOkIyOXj4wKBwEBQfC3cNcHDluRku5TKEl1p1E6lfjeF3Bmqyv+ZjEPIMqet91W6
60qP9C+Ucb19IpF2kAf6DlIW4ErURcCLGHSGbL7YKZV4f9OVqNsXVtr2a9h9wk/+
vIqeZgrpIb63Xqt8n/Gy6jd+QaoU4LfQRXMo+2zJ9theWq0K+2Mm2NHSQzXpziiH
kZygxe1ZxCMRHSoijeOZDOnc8aLjqjizbxOwfocKw3PTBWhxeqhcaXJuxnt7tFHX
tKdW03Eiu2j+XQKBwQCdyCcX1+4wfWNcFa9Aht6m+wjc4W1YOnuhgRMQYqHIoi+k
XdU++Pq2th0MzpVg9cXR9TEL+FMIgeLFvNoxcLo13KMNsWZh98jNRxsnkvouHvMG
Xi76MwiNDBYljLCBwIOOeBJp5DDTpX2gDPW2sFI7yapJA7JNrurhEJkPpm+dKU7s
nvEUEJIx63Tn4dyqgfGGf0Pci9wReZgVaMA1/eZtovXLD0iVDy6osKlsVRey0xyj
gvdTPYk1Byjm/1yU0scCgcEAgCzLcqc7O1t9kXNo48Lh+O3wtxYVZ0FTHAz0TtcR
oVaRaok3aSEkCuZlBf4a9CJCKxzkDPg7dNNcUt5ng16XxJoEcIgf8FeS+BZS9L0O
bLOQoAggW41OlRnX9yQIti9w/MR+qRzKSftTZcP8ySls4SCphlqsx/a7JXncgwI8
QmML5MzfffKdB1RNs5yVWyzSsxHgmVGLcA9UziomcUPCrpXp10C/yzGnMPAyAwlo
9k5AET80ZLKc7XYQ0NxI2yCf
-----END PRIVATE KEY-----

View file

@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEWTCCAsGgAwIBAgIQBA3zYaPnHKhRmKC37lWvEjANBgkqhkiG9w0BAQsFADBF
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExDTALBgNVBAsTBHRlc3Qx
FDASBgNVBAMTC21rY2VydCB0ZXN0MB4XDTIwMDgyNDE5NDIwOVoXDTMwMDgyNDE5
NDIwOVowRTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMQ0wCwYDVQQL
EwR0ZXN0MRQwEgYDVQQDEwtta2NlcnQgdGVzdDCCAaIwDQYJKoZIhvcNAQEBBQAD
ggGPADCCAYoCggGBAK5vzHoxEjVpZlWTup+lCfsIrp8Ic1x4GFJAUwcEldAsQB7f
i42AXWH41AYzbNooNnyEixE1mrR1X+BfJ3sAwDkLwPLId+rOiIcl5NcqioYSaL8z
Jd+cevo3itCmgb3tJsAIph806H8wPTmAiDnUuttMrUbMXKDQBWe2y+abevc00e/8
EkpUpX7YdnHUPzfFwGy10sMA922ZTfNJPOLFBgNOXOzWBSsk98kCLWwAwz9FsMpO
aCxgminEANFiV04i9kRmo+u6kidSLi+IUSixvR2lJJ4eQoGBWXzVfauj5Yfi+B+h
4aSm7qaHrsV83VaWMx/rcTrI4QFyrET5Vz077Kyu44OeZrV34N9egehkidSHNQzu
dN1ux+2ZvQLlsUDe2zXpYZnWDbUeLuY0fYx1baEvJGeABT0AdNY5t0HFvgwGYFIX
lkgSVyx8sAGKUcbnTwvZlgz66o5vSJYAxxXKuWLsRoMQ4X+hS/tawMB6TAYop/L1
7F9aHDv7Kf5Rgbig9QIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/
BAgwBgEB/wIBADAdBgNVHQ4EFgQU0t8UaNj7xry1h0qnTAm8Sxv69aMwDQYJKoZI
hvcNAQELBQADggGBAFZT6Zdg+tt+8t6Bo9Boe8uOKnqrCSuOCyMIajDLgijPRlHf
iJRggRjGT2Ig7c0nzL5SfeuExoMPMUmkfNAKki3VhK7cxLijDtn4fOmyyW5OO7AT
zwSmOyakHXq4ip3klysNGVPzxjwHBuK5rCdPa2X1WXN4PeM6NQvGZB34hQ1962om
1gad4YardZ81fVLJfOlCtIPD87TSreVGxiawUIAAGWgDuVMouN4PvqTUyEmorgxi
hSaiVDCSlS/nuW5fuOGzZ1Ko9UhbCsmO3bbLzXKcjuwKeyzgyjozHMyx5gUhhOFk
kqDIuIven3j+uLke0WAK++Z11vM8fVn0wB80RqubuTbqJzvH3w0R/PWVd0yAMFNu
Y2Z+AZ0OwMm9BtqfwoW5PZSIMF06q6IbLmuLEH/5dE9xDN0s5Ia8gn7ySYqso+62
yJjURRgGJeXLkrjfeSav39D0bg+JCB7J63Z7BCz6/Jv1TL45yWbeMmtqFPH6nS5t
25uIk/1regWTCajVMg==
-----END CERTIFICATE-----

View file

@ -1,70 +0,0 @@
# Protected application
server {
listen 80;
listen 443 ssl http2;
server_name verify.localhost.pomerium.io;
ssl_certificate /etc/nginx/nginx.pem;
ssl_certificate_key /etc/nginx/nginx-key.pem;
location = /ext_authz {
internal;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-Proto "";
proxy_set_header Host fwdauth.localhost.pomerium.io;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_ssl_server_name on;
proxy_pass_request_headers on;
client_max_body_size 1m;
# Pass the extracted client certificate to the auth provider
set $target http://pomerium/verify?uri=$scheme://$http_host$request_uri;
# uncomment to emulate nginx-ingress behavior
# set $target http://pomerium/verify?uri=$scheme://$http_host$request_uri&rd=$pass_access_scheme://$http_host$escaped_request_uri;
proxy_pass $target;
}
location @authredirect {
internal;
add_header Set-Cookie $auth_cookie;
# uncomment to emulate nginx-ingress behavior
# return 302 https://fwdauth.localhost.pomerium.io/?uri=$scheme://$host$request_uri&rd=$pass_access_scheme://$http_host$escaped_request_uri;
return 302
https://fwdauth.localhost.pomerium.io/?uri=$scheme://$host$request_uri;
}
location / {
proxy_pass http://verify:8000;
include /etc/nginx/proxy.conf;
# If we get a 401, respond with a named location
error_page 401 = @authredirect;
# this location requires authentication
auth_request /ext_authz;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
}
}

View file

@ -1,19 +0,0 @@
# Pomerium as forward-auth provider for Traefik on Kubernetes
Run this demo locally on your kubernetes capable workstation or:
- use `kubectl port-forward service/traefik 80:80 443:443`
- replace `localhost.pomerium.io` with your own domain
## Includes
- Authentication and Authorization managed by pomerium
- Routing / reverse proxying handled by traefik
- Installation using upstream `helm` charts
## How
- Update `values/pomerium.yaml` for your e-mail address, if not using gmail/google.
- Replace IdP secrets in `values/pomerium.yaml`.
- Run `./add_repos.sh` from this directory.
- Run `./install.sh` from this directory.
- Navigate to `https://hello.localhost.pomerium.io`

View file

@ -1,5 +0,0 @@
#!/bin/bash -x
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add pomerium https://helm.pomerium.io
helm repo add traefik https://containous.github.io/traefik-helm-chart

View file

@ -1,10 +0,0 @@
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: auth
spec:
forwardAuth:
address: https://pomerium-proxy.pomerium
tls:
insecureSkipVerify: true
trustForwardHeader: true

View file

@ -1,31 +0,0 @@
#!/bin/bash -x
kubectl create namespace pomerium
# Create shared TLS secret
kubectl create secret tls wildcard-tls \
--namespace pomerium \
--cert=_wildcard.localhost.pomerium.io.pem \
--key=_wildcard.localhost.pomerium.io-key.pem
# Install Traefik helm chart
helm upgrade --install --wait \
--namespace pomerium \
traefik traefik/traefik \
--values values/traefik.yaml
# Install Pomerium helm chart
helm upgrade --install --wait \
--namespace pomerium \
pomerium pomerium/pomerium \
--values values/pomerium.yaml
# Create middleware
kubectl --namespace pomerium apply -f crds/middleware.yaml
# Install hello app
helm upgrade --install --wait \
--namespace pomerium \
--version 6.2.1 \
hello bitnami/nginx \
--values values/hello.yaml

View file

@ -1,15 +0,0 @@
ingress:
enabled: true
hosts:
- name: hello.localhost.pomerium.io
path: /
annotations:
traefik.ingress.kubernetes.io/router.middlewares: pomerium-auth@kubernetescrd
traefik.ingress.kubernetes.io/router.tls: "true"
tls:
- hosts:
- hello.localhost.pomerium.io
secretName: wildcard-tls
service:
type: ClusterIP

View file

@ -1,27 +0,0 @@
authenticate:
idp:
provider: REPLACEME
url: REPLACEME
clientID: REPLACEME
clientSecret: REPLACEME
config:
rootDomain: localhost.pomerium.io
sharedSecret: R0+XRoGVpcoi4PfB8tMlvnrS5XUasO+D1frAEdYcYjs=
cookieSecret: FLPCOQKigK5EQnyXlBhchl5fgzNKqi3ubtvOGt477Dg=
generateTLS: true
routes:
- from: https://hello.localhost.pomerium.io
to: http://hello-nginx
policy:
- allow:
or:
- domain:
is: gmail.com
ingress:
annotations:
traefik.ingress.kubernetes.io/router.tls: "true"
secretName: wildcard-tls
forwardAuth:
enabled: true
internal: true

View file

@ -1,3 +0,0 @@
additionalArguments:
- "--serverstransport.insecureskipverify=true"
- "--entryPoints.websecure.forwardedHeaders.insecure"

View file

@ -1,17 +0,0 @@
# Pomerium as forward-auth provider for Traefik
Run this demo locally on your docker-compose capable workstation, or replace `localhost.pomerium.io` with your own domain if running on a server.
## Includes
- Authentication and Authorization managed by pomerium
- Routing / reverse proxying handled by traefik
## How
- Update `config.yaml` for your e-mail address, if not using gmail/google.
- Replace secrets in `config.yaml`.
- Run `docker-compose up` from this directory.
- Navigate to `https://verify.localhost.pomerium.io`
- ???
- Profit

View file

@ -1,27 +0,0 @@
# Main configuration flags : https://www.pomerium.com/docs/reference/
pomerium_debug: true
address: :80
cookie_secret: YVFTMIfW8yBJw+a6sYwdW8rHbU+IAAV/SUkCTg9Jtpo=
shared_secret: 80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ=
idp_provider: "google"
idp_client_id: REPLACEME
idp_client_secret: REPLACEME
insecure_server: true
forward_auth_url: http://pomerium
authenticate_service_url: https://authenticate.localhost.pomerium.io
jwt_claims_headers: email,groups,user
routes:
- from: https://verify.localhost.pomerium.io
to: https://httpbin
policy:
- allow:
or:
- domain:
is: pomerium.io
- domain:
is: gmail.com
pass_identity_headers: true

View file

@ -1,44 +0,0 @@
version: "3"
services:
traefik:
image: traefik:v2.1
command:
- "--accesslog=true"
- "--api.insecure=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.forwardedHeaders.insecure"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker=true"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
verify:
image: pomerium/verify:latest
labels:
- "traefik.http.middlewares.pomerium.forwardauth.authResponseHeaders=X-Pomerium-Claim-Email,X-Pomerium-Claim-User,X-Pomerium-Claim-Groups,X-Pomerium-Jwt-Assertion"
- "traefik.http.middlewares.pomerium.forwardauth.address=http://pomerium/"
- "traefik.http.middlewares.pomerium.forwardauth.trustForwardHeader=true"
- "traefik.http.routers.verify.middlewares=pomerium@docker"
- "traefik.enable=true"
- "traefik.http.routers.verify.rule=Host(`verify.localhost.pomerium.io`)"
- "traefik.http.routers.verify.entrypoints=websecure"
- "traefik.http.routers.verify.tls=true"
pomerium:
image: pomerium/pomerium:latest
volumes:
- ./config.yaml:/pomerium/config.yaml:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.pomerium.rule=Host(`authenticate.localhost.pomerium.io`)"
- "traefik.http.routers.pomerium.entrypoints=websecure"
- "traefik.http.routers.pomerium.tls=true"
expose:
- 80

View file

@ -1,25 +0,0 @@
# dashboard-forwardauth.ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: dashboard-forwardauth
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt-prod" # see `letsencrypt.issuer.yaml`
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/auth-url: "https://forwardauth.domain.example/verify?uri=$scheme://$host$request_uri"
nginx.ingress.kubernetes.io/auth-signin: "https://forwardauth.domain.example?uri=$scheme://$host$request_uri"
spec:
tls:
- hosts:
- dashboard-forwardauth.domain.example
secretName: dashboard-forwardauth-tls
rules:
- host: dashboard-forwardauth.domain.example
http:
paths:
- path: /
backend:
serviceName: helm-dashboard-kubernetes-dashboard
servicePort: https

View file

@ -18,20 +18,12 @@ func TestAuthorization(t *testing.T) {
accessType := []string{"direct", "api"}
for _, at := range accessType {
t.Run(at, func(t *testing.T) {
var withAPI, withForwardAuth flows.AuthenticateOption
var withAPI flows.AuthenticateOption
if at == "api" {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
withAPI = flows.WithAPI()
}
if ClusterType == "nginx" {
withForwardAuth = flows.WithForwardAuth(true)
}
t.Run("public", func(t *testing.T) {
client := getClient()
@ -53,7 +45,7 @@ func TestAuthorization(t *testing.T) {
t.Run("allowed", func(t *testing.T) {
client := getClient()
res, err := flows.Authenticate(ctx, client, mustParseURL("https://httpdetails.localhost.pomerium.io/by-domain"),
withAPI, withForwardAuth, flows.WithEmail("user1@dogs.test"))
withAPI, flows.WithEmail("user1@dogs.test"))
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, res.StatusCode, "expected OK for dogs.test")
}
@ -61,7 +53,7 @@ func TestAuthorization(t *testing.T) {
t.Run("not allowed", func(t *testing.T) {
client := getClient()
res, err := flows.Authenticate(ctx, client, mustParseURL("https://httpdetails.localhost.pomerium.io/by-domain"),
withAPI, withForwardAuth, flows.WithEmail("user1@cats.test"))
withAPI, flows.WithEmail("user1@cats.test"))
if assert.NoError(t, err) {
assertDeniedAccess(t, res, "expected Forbidden for cats.test, but got: %d", res.StatusCode)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -48,11 +48,6 @@ func TestDashboard(t *testing.T) {
}
func TestHealth(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*30)
defer clearTimeout()

View file

@ -13,16 +13,14 @@ import (
"time"
"github.com/pomerium/pomerium/integration/forms"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/urlutil"
)
const (
authenticateHostname = "authenticate.localhost.pomerium.io"
forwardAuthenticateHostname = "forward-authenticate.localhost.pomerium.io"
idpHostname = "mock-idp.localhost.pomerium.io"
pomeriumCallbackPath = "/.pomerium/callback/"
pomeriumAPIPath = "/.pomerium/api/v1/login"
authenticateHostname = "authenticate.localhost.pomerium.io"
idpHostname = "mock-idp.localhost.pomerium.io"
pomeriumCallbackPath = "/.pomerium/callback/"
pomeriumAPIPath = "/.pomerium/api/v1/login"
)
type authenticateConfig struct {
@ -30,7 +28,6 @@ type authenticateConfig struct {
groups []string
tokenExpiration time.Duration
apiPath string
forwardAuth bool
}
// An AuthenticateOption is an option for authentication.
@ -48,13 +45,6 @@ func getAuthenticateConfig(options ...AuthenticateOption) *authenticateConfig {
return cfg
}
// WithForwardAuth enables/disables forward auth.
func WithForwardAuth(fa bool) AuthenticateOption {
return func(cfg *authenticateConfig) {
cfg.forwardAuth = fa
}
}
// WithEmail sets the email to use.
func WithEmail(email string) AuthenticateOption {
return func(cfg *authenticateConfig) {
@ -145,7 +135,7 @@ func Authenticate(ctx context.Context, client *http.Client, url *url.URL, option
}
// (2) redirect to idp
for req.URL.Hostname() == authenticateHostname || req.URL.Hostname() == forwardAuthenticateHostname {
for req.URL.Hostname() == authenticateHostname {
res, err = client.Do(req)
if err != nil {
return nil, err
@ -201,34 +191,10 @@ func Authenticate(ctx context.Context, client *http.Client, url *url.URL, option
}
// (5) finally to callback
if !cfg.forwardAuth && req.URL.Path != pomeriumCallbackPath {
if req.URL.Path != pomeriumCallbackPath {
return nil, fmt.Errorf("expected to redirect 5 back to %s, but got %s", pomeriumCallbackPath, req.URL.String())
}
if cfg.forwardAuth {
for i := 0; ; i++ {
res, err = client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != 302 {
break
}
originalURL := req.URL.String()
req, err = requestFromRedirectResponse(ctx, res, req)
if err != nil {
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
}
log.Info(ctx).
Int("count", i).
Str("from", originalURL).
Str("to", req.URL.String()).
Msg("forward-auth redirect")
}
return res, err
}
res, err = client.Do(req)
if err != nil {
return nil, err

View file

@ -53,11 +53,6 @@ func TestQueryStringParams(t *testing.T) {
}
func TestCORS(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx := context.Background()
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
defer clearTimeout()
@ -97,11 +92,6 @@ func TestCORS(t *testing.T) {
}
func TestPreserveHostHeader(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx := context.Background()
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
defer clearTimeout()
@ -159,11 +149,6 @@ func TestPreserveHostHeader(t *testing.T) {
}
func TestSetRequestHeaders(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx := context.Background()
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
defer clearTimeout()
@ -221,11 +206,6 @@ func TestRemoveRequestHeaders(t *testing.T) {
}
func TestWebsocket(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx := context.Background()
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
defer clearTimeout()
@ -290,11 +270,6 @@ func TestGoogleCloudRun(t *testing.T) {
}
func TestLoadBalancer(t *testing.T) {
if ClusterType == "traefik" || ClusterType == "nginx" {
t.Skip()
return
}
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Minute*10)
defer clearTimeout()

View file

@ -1,184 +0,0 @@
local utils = import '../utils.libsonnet';
local Routes = (import './routes.libsonnet').Routes;
local ProxyConfig() =
|||
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
proxy_set_header Proxy "";
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_redirect off;
|||;
local AuthenticateConfig() =
|||
server {
listen 443 ssl;
server_name authenticate.localhost.pomerium.io forward-authenticate.localhost.pomerium.io;
ssl_certificate /etc/_wildcard.localhost.pomerium.io.pem;
ssl_certificate_key /etc/_wildcard.localhost.pomerium.io-key.pem;
location / {
proxy_pass http://pomerium;
include /etc/nginx/proxy.conf;
}
}
upstream pomerium {
server pomerium;
}
|||;
local AuthzConfig() =
|||
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-Proto "";
proxy_set_header Host forward-authenticate.localhost.pomerium.io;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
proxy_buffering off;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_ssl_server_name on;
proxy_pass_request_headers on;
client_max_body_size 1m;
set $target http://pomerium/verify?uri=$scheme://$http_host$request_uri;
proxy_pass $target;
|||;
local RouteLocationConfig(route) =
local rule =
if std.objectHas(route, 'prefix') then '^~ ' + route.prefix
else if std.objectHas(route, 'path') then '= ' + route.path
else '/';
local to =
if std.isArray(route.to) then route.to[0]
else route.to;
|||
location %s {
proxy_pass %s;
include /etc/nginx/proxy.conf;
# If we get a 401, respond with a named location
error_page 401 = @authredirect;
# this location requires authentication
auth_request /ext_authz;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
}
||| % [rule, to];
local DomainServerConfig(domain, routes) =
local locations = std.join('\n', std.map(function(route) RouteLocationConfig(route), routes));
|||
server {
listen 443 ssl http2;
server_name %s;
ssl_certificate /etc/_wildcard.localhost.pomerium.io.pem;
ssl_certificate_key /etc/_wildcard.localhost.pomerium.io-key.pem;
location = /ext_authz {
internal;
include /etc/nginx/authz.conf;
}
location @authredirect {
internal;
add_header Set-Cookie $auth_cookie;
return 302 https://forward-authenticate.localhost.pomerium.io/?uri=$scheme://$host$request_uri;
}
%s
}
||| % [domain, locations];
local RoutesConfig(mode, idp, dns_suffix) =
local routes = Routes(mode, idp, dns_suffix);
local domains = std.set(std.map(function(route) utils.ParseURL(route.from).host, routes));
std.join('\n', [
local routesForDomain = std.filter(function(route)
local url = utils.ParseURL(route.from);
url.host == domain && (url.scheme == 'http' || url.scheme == 'https'),
routes);
DomainServerConfig(domain, routesForDomain)
for domain in domains
]);
local WriteFile(path, contents) =
|||
cat <<-'END_OF_NGINX' | tee %s
%s
END_OF_NGINX
||| % [path, std.strReplace(contents, '$', '$$')];
local Command(mode, idp, dns_suffix) =
[
'sh',
'-c',
std.join('\n\n', [
WriteFile('/etc/nginx/conf.d/authenticate.conf', AuthenticateConfig()),
WriteFile('/etc/nginx/conf.d/routes.conf', RoutesConfig(mode, idp, dns_suffix)),
WriteFile('/etc/nginx/authz.conf', AuthzConfig()),
WriteFile('/etc/nginx/proxy.conf', ProxyConfig()),
WriteFile('/etc/_wildcard.localhost.pomerium.io.pem', importstr '../files/trusted.pem'),
WriteFile('/etc/_wildcard.localhost.pomerium.io-key.pem', importstr '../files/trusted-key.pem'),
"nginx -g 'daemon off;'",
]),
];
function(mode, idp, dns_suffix='') {
local image = 'nginx:1.21.1',
compose: {
services: utils.ComposeService('nginx', {
image: image,
depends_on: {
'pomerium-ready': {
condition: 'service_completed_successfully',
},
},
entrypoint: Command(mode, idp, dns_suffix),
ports: [
'80:80/tcp',
'443:443/tcp',
],
}, ['mock-idp.localhost.pomerium.io']),
},
}

View file

@ -103,12 +103,6 @@ local Environment(mode, idp, dns_suffix) =
DATABROKER_SERVICE_URL: 'https://pomerium-databroker:5443',
GRPC_ADDRESS: ':5443',
GRPC_INSECURE: 'false',
} else if mode == 'traefik' then {
FORWARD_AUTH_URL: 'https://forward-authenticate.localhost.pomerium.io',
} else if mode == 'nginx' then {
ADDRESS: ':80',
INSECURE_SERVER: 'true',
FORWARD_AUTH_URL: 'https://forward-authenticate.localhost.pomerium.io',
} else {};
local ComposeService(name, definition, additionalAliases=[]) =
@ -186,24 +180,6 @@ function(mode, idp, dns_suffix='') {
'9901:9901/tcp',
],
}, ['mock-idp.localhost.pomerium.io'])
else if mode == 'traefik' || mode == 'nginx' then
ComposeService(name, {
image: image,
environment: environment,
}, ['authenticate.localhost.pomerium.io', 'forward-authenticate.localhost.pomerium.io']) +
ComposeService(name + '-ready', {
image: 'powerman/dockerize:0.16.3',
command: [
'-skip-tls-verify',
'-wait',
if mode == 'nginx' then
'http://' + name + ':80/healthz'
else
'https://' + name + ':443/healthz',
'-timeout',
'10m',
],
})
else
ComposeService(name, {
image: image,

View file

@ -1,180 +0,0 @@
local utils = import '../utils.libsonnet';
local Routes = (import './routes.libsonnet').Routes;
local StaticConfig() =
{
global: {
checkNewVersion: false,
sendAnonymousUsage: false,
},
log: {
level: 'DEBUG',
},
accessLog: {},
entryPoints: {
web: {
address: ':80',
forwardedheaders: {
insecure: true,
},
},
websecure: {
address: ':443',
forwardedheaders: {
insecure: true,
},
},
},
api: {
insecure: true,
},
providers: {
file: {
filename: 'traefik-dynamic.yaml',
},
},
};
local Rule(route) =
local url = utils.ParseURL(route.from);
std.join(
' && ',
['Host(`' + url.host + '`)'] +
(if std.objectHas(route, 'prefix') then
['PathPrefix(`' + route.prefix + '`)'] else []) +
(if std.objectHas(route, 'path') then
['Path(`' + route.path + '`)'] else [])
);
local DynamicConfig(mode, idp, dns_suffix='') =
{
local routes = Routes(mode, idp, dns_suffix) + [
{
from: 'https://authenticate.localhost.pomerium.io',
to: 'https://pomerium' + dns_suffix + ':443',
allow_public_unauthenticated_access: true,
tls_skip_verify: true,
preserve_host_header: true,
},
],
tls: {
certificates: [{
certFile: '_wildcard.localhost.pomerium.io.pem',
keyFile: '_wildcard.localhost.pomerium.io-key.pem',
}],
},
http: {
serversTransports: {
insecure: {
insecureSkipVerify: true,
},
},
routers: {
['route%d' % i]: {
service: 'route%d' % i,
rule: Rule(routes[i]),
tls: {},
middlewares:
(if routes[i].from == 'https://authenticate.localhost.pomerium.io' then
[]
else
['authz']) +
(if std.objectHas(routes[i], 'set_request_headers') then
['set-request-headers-%d' % i]
else
[]),
}
for i in std.range(0, std.length(routes) - 1)
},
services: {
['route%d' % i]: {
loadBalancer:
{
servers: [{
url: routes[i].to,
}],
} +
(if std.startsWith(routes[i].to, 'https://') then
{ serversTransport: 'insecure' }
else
{}) +
(if std.objectHas(routes[i], 'preserve_host_header') && routes[i].preserve_host_header then
{ passHostHeader: true }
else
{ passHostHeader: false }),
}
for i in std.range(0, std.length(routes) - 1)
},
middlewares: {
authz: {
forwardAuth: {
address: 'https://forward-authenticate.localhost.pomerium.io',
trustForwardHeader: true,
authResponseHeaders: ['x-pomerium-jwt-assertion', 'x-pomerium-claim-email', 'authorization'],
tls: {
insecureSkipVerify: true,
},
},
},
} + {
['set-request-headers-%d' % i]: {
headers: {
customRequestHeaders: {
[k]: routes[i].set_request_headers[k]
for k in std.objectFields(routes[i].set_request_headers)
},
},
}
for i in std.range(0, std.length(routes) - 1)
if std.objectHas(routes[i], 'set_request_headers')
},
},
};
local Command(mode, idp, dns_suffix='') =
[
'sh',
'-c',
|||
cat <<-'END_OF_TRAEFIK' | tee traefik.yaml
%s
END_OF_TRAEFIK
cat <<-'END_OF_TRAEFIK' | tee traefik-dynamic.yaml
%s
END_OF_TRAEFIK
cat <<-'END_OF_TRAEFIK' | tee _wildcard.localhost.pomerium.io.pem
%s
END_OF_TRAEFIK
cat <<-'END_OF_TRAEFIK' | tee _wildcard.localhost.pomerium.io-key.pem
%s
END_OF_TRAEFIK
traefik -configFile=traefik.yaml
||| % [
std.manifestJsonEx(StaticConfig(), ' '),
std.manifestJsonEx(DynamicConfig(mode, idp, dns_suffix), ' '),
importstr '../files/trusted.pem',
importstr '../files/trusted-key.pem',
],
];
function(mode, idp, dns_suffix='') {
local image = 'traefik:latest',
compose: {
services:
utils.ComposeService('traefik', {
image: image,
depends_on: {
pomerium: {
condition: 'service_started',
},
},
command: Command(mode, idp, dns_suffix),
ports: [
'80:80/tcp',
'443:443/tcp',
],
}, ['authenticate.localhost.pomerium.io', 'mock-idp.localhost.pomerium.io']),
},
}

View file

@ -1 +0,0 @@
(import '../../deployments/nginx.libsonnet')('oidc')

View file

@ -1 +0,0 @@
(import '../../deployments/traefik.libsonnet')('oidc')

View file

@ -1,17 +0,0 @@
local utils = import '../utils.libsonnet';
function(idp) utils.Merge([
(import '../backends/fortio.libsonnet')().compose,
(import '../backends/httpdetails.libsonnet')().compose,
(import '../backends/mock-idp.libsonnet')(idp).compose,
(import '../backends/pomerium.libsonnet')('nginx', idp).compose,
(import '../backends/postgres.libsonnet')().compose,
(import '../backends/verify.libsonnet')('nginx').compose,
(import '../backends/websocket-echo.libsonnet')().compose,
(import '../backends/nginx.libsonnet')('single', idp).compose,
{
networks: {
main: {},
},
},
])

View file

@ -1,17 +0,0 @@
local utils = import '../utils.libsonnet';
function(idp) utils.Merge([
(import '../backends/fortio.libsonnet')().compose,
(import '../backends/httpdetails.libsonnet')().compose,
(import '../backends/mock-idp.libsonnet')(idp).compose,
(import '../backends/pomerium.libsonnet')('traefik', idp).compose,
(import '../backends/postgres.libsonnet')().compose,
(import '../backends/traefik.libsonnet')('single', idp).compose,
(import '../backends/verify.libsonnet')('traefik').compose,
(import '../backends/websocket-echo.libsonnet')().compose,
{
networks: {
main: {},
},
},
])

View file

@ -12,7 +12,6 @@ import (
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/handlers"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry"
"github.com/pomerium/pomerium/internal/telemetry/requestid"
@ -39,7 +38,6 @@ func (srv *Server) addHTTPMiddleware(root *mux.Router, cfg *config.Config) {
Msg("http-request")
}))
root.Use(gorillahandlers.RecoveryHandler())
root.Use(log.HeadersHandler(httputil.HeadersXForwarded))
root.Use(log.RemoteAddrHandler("ip"))
root.Use(log.UserAgentHandler("user_agent"))
root.Use(log.RefererHandler("referer"))

View file

@ -42,46 +42,6 @@ var HeadersContentSecurityPolicy = map[string]string{
"Referrer-Policy": "Same-origin",
}
// Forward headers contains information from the client-facing side of proxy
// servers that is altered or lost when a proxy is involved in the path of the
// request.
//
// https://tools.ietf.org/html/rfc7239
// https://en.wikipedia.org/wiki/X-Forwarded-For
const (
HeaderForwardedFor = "X-Forwarded-For"
HeaderForwardedHost = "X-Forwarded-Host"
HeaderForwardedMethod = "X-Forwarded-Method" // traefik
HeaderForwardedPort = "X-Forwarded-Port"
HeaderForwardedProto = "X-Forwarded-Proto"
HeaderForwardedServer = "X-Forwarded-Server"
HeaderForwardedURI = "X-Forwarded-Uri" // traefik
HeaderOriginalMethod = "X-Original-Method" // nginx
HeaderOriginalURL = "X-Original-Url" // nginx
HeaderRealIP = "X-Real-Ip"
HeaderSentFrom = "X-Sent-From"
)
// HeadersXForwarded is the slice of the header keys used to contain information
// from the client-facing side of proxy servers that is altered or lost when a
// proxy is involved in the path of the request.
//
// https://tools.ietf.org/html/rfc7239
// https://en.wikipedia.org/wiki/X-Forwarded-For
var HeadersXForwarded = []string{
HeaderForwardedFor,
HeaderForwardedHost,
HeaderForwardedMethod,
HeaderForwardedPort,
HeaderForwardedProto,
HeaderForwardedServer,
HeaderForwardedURI,
HeaderOriginalMethod,
HeaderOriginalURL,
HeaderRealIP,
HeaderSentFrom,
}
// PomeriumJWTHeaderName returns the header name set by pomerium for given JWT claim field.
func PomeriumJWTHeaderName(claim string) string {
return "x-pomerium-claim-" + claim

View file

@ -1,47 +0,0 @@
package urlutil
import (
"net/http"
"net/url"
"strings"
)
// Forward headers contains information from the client-facing side of proxy
// servers that is altered or lost when a proxy is involved in the path of the
// request.
//
// https://tools.ietf.org/html/rfc7239
// https://en.wikipedia.org/wiki/X-Forwarded-For
const (
HeaderForwardedHost = "X-Forwarded-Host"
HeaderForwardedProto = "X-Forwarded-Proto"
HeaderForwardedURI = "X-Forwarded-Uri" // traefik
HeaderOriginalURL = "X-Original-Url" // nginx
)
// GetForwardAuthURL gets the forward-auth URL for the given request.
func GetForwardAuthURL(r *http.Request) *url.URL {
urqQuery := r.URL.Query().Get("uri")
u, _ := ParseAndValidateURL(urqQuery)
if u == nil {
u = &url.URL{
Scheme: r.Header.Get(HeaderForwardedProto),
Host: r.Header.Get(HeaderForwardedHost),
}
rawPath := r.Header.Get(HeaderForwardedURI)
if idx := strings.Index(rawPath, "?"); idx >= 0 {
u.Path = rawPath[:idx]
u.RawQuery = rawPath[idx+1:]
} else {
u.Path = rawPath
}
}
originalURL := r.Header.Get(HeaderOriginalURL)
if originalURL != "" {
k, _ := ParseAndValidateURL(originalURL)
if k != nil {
u = k
}
}
return u
}

View file

@ -1,22 +0,0 @@
package urlutil
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetForwardAuthURL(t *testing.T) {
t.Run("double-escaping", func(t *testing.T) {
req, err := http.NewRequest("GET", "https://example.com", nil)
require.NoError(t, err)
req.Header.Set("X-Forwarded-Proto", "https")
req.Header.Set("X-Forwarded-Host", "protected-host.tld")
req.Header.Set("X-Forwarded-Uri", "/example?a=b&c=d")
u := GetForwardAuthURL(req)
assert.Equal(t, "https://protected-host.tld/example?a=b&c=d", u.String())
})
}

View file

@ -10,12 +10,10 @@ const (
QueryEnrollmentToken = "pomerium_enrollment_token" //nolint
QueryIdentityProviderID = "pomerium_idp_id"
QueryIsProgrammatic = "pomerium_programmatic"
QueryForwardAuth = "pomerium_forward_auth"
QueryPomeriumJWT = "pomerium_jwt"
QuerySession = "pomerium_session"
QuerySessionEncrypted = "pomerium_session_encrypted"
QueryRedirectURI = "pomerium_redirect_uri"
QueryForwardAuthURI = "uri"
)
// URL signature based query params used for verifying the authenticity of a URL.

View file

@ -199,6 +199,7 @@ type Selector struct {
unknownFields protoimpl.UnknownFields
// Types that are assignable to Filter:
//
// *Selector_All
// *Selector_Tag
// *Selector_IdFilter_
@ -828,6 +829,7 @@ type Connection struct {
// the URL of the pomerium server to connect to
PomeriumUrl *string `protobuf:"bytes,4,opt,name=pomerium_url,json=pomeriumUrl,proto3,oneof" json:"pomerium_url,omitempty"`
// Types that are assignable to TlsOptions:
//
// *Connection_DisableTlsVerification
// *Connection_CaCert
TlsOptions isConnection_TlsOptions `protobuf_oneof:"tls_options"`

View file

@ -144,6 +144,7 @@ type RouteRewriteHeader struct {
Header string `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// Types that are assignable to Matcher:
//
// *RouteRewriteHeader_Prefix
Matcher isRouteRewriteHeader_Matcher `protobuf_oneof:"matcher"`
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
@ -939,21 +940,21 @@ type Settings struct {
SigningKey *string `protobuf:"bytes,36,opt,name=signing_key,json=signingKey,proto3,oneof" json:"signing_key,omitempty"`
SetResponseHeaders map[string]string `protobuf:"bytes,69,rep,name=set_response_headers,json=setResponseHeaders,proto3" json:"set_response_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// repeated string jwt_claims_headers = 37;
JwtClaimsHeaders map[string]string `protobuf:"bytes,63,rep,name=jwt_claims_headers,json=jwtClaimsHeaders,proto3" json:"jwt_claims_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
DefaultUpstreamTimeout *durationpb.Duration `protobuf:"bytes,39,opt,name=default_upstream_timeout,json=defaultUpstreamTimeout,proto3,oneof" json:"default_upstream_timeout,omitempty"`
MetricsAddress *string `protobuf:"bytes,40,opt,name=metrics_address,json=metricsAddress,proto3,oneof" json:"metrics_address,omitempty"`
MetricsBasicAuth *string `protobuf:"bytes,64,opt,name=metrics_basic_auth,json=metricsBasicAuth,proto3,oneof" json:"metrics_basic_auth,omitempty"`
MetricsCertificate *Settings_Certificate `protobuf:"bytes,65,opt,name=metrics_certificate,json=metricsCertificate,proto3,oneof" json:"metrics_certificate,omitempty"`
MetricsClientCa *string `protobuf:"bytes,66,opt,name=metrics_client_ca,json=metricsClientCa,proto3,oneof" json:"metrics_client_ca,omitempty"`
MetricsClientCaFile *string `protobuf:"bytes,67,opt,name=metrics_client_ca_file,json=metricsClientCaFile,proto3,oneof" json:"metrics_client_ca_file,omitempty"`
TracingProvider *string `protobuf:"bytes,41,opt,name=tracing_provider,json=tracingProvider,proto3,oneof" json:"tracing_provider,omitempty"`
TracingSampleRate *float64 `protobuf:"fixed64,42,opt,name=tracing_sample_rate,json=tracingSampleRate,proto3,oneof" json:"tracing_sample_rate,omitempty"`
TracingJaegerCollectorEndpoint *string `protobuf:"bytes,43,opt,name=tracing_jaeger_collector_endpoint,json=tracingJaegerCollectorEndpoint,proto3,oneof" json:"tracing_jaeger_collector_endpoint,omitempty"`
TracingJaegerAgentEndpoint *string `protobuf:"bytes,44,opt,name=tracing_jaeger_agent_endpoint,json=tracingJaegerAgentEndpoint,proto3,oneof" json:"tracing_jaeger_agent_endpoint,omitempty"`
TracingZipkinEndpoint *string `protobuf:"bytes,45,opt,name=tracing_zipkin_endpoint,json=tracingZipkinEndpoint,proto3,oneof" json:"tracing_zipkin_endpoint,omitempty"`
GrpcAddress *string `protobuf:"bytes,46,opt,name=grpc_address,json=grpcAddress,proto3,oneof" json:"grpc_address,omitempty"`
GrpcInsecure *bool `protobuf:"varint,47,opt,name=grpc_insecure,json=grpcInsecure,proto3,oneof" json:"grpc_insecure,omitempty"`
ForwardAuthUrl *string `protobuf:"bytes,50,opt,name=forward_auth_url,json=forwardAuthUrl,proto3,oneof" json:"forward_auth_url,omitempty"`
JwtClaimsHeaders map[string]string `protobuf:"bytes,63,rep,name=jwt_claims_headers,json=jwtClaimsHeaders,proto3" json:"jwt_claims_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
DefaultUpstreamTimeout *durationpb.Duration `protobuf:"bytes,39,opt,name=default_upstream_timeout,json=defaultUpstreamTimeout,proto3,oneof" json:"default_upstream_timeout,omitempty"`
MetricsAddress *string `protobuf:"bytes,40,opt,name=metrics_address,json=metricsAddress,proto3,oneof" json:"metrics_address,omitempty"`
MetricsBasicAuth *string `protobuf:"bytes,64,opt,name=metrics_basic_auth,json=metricsBasicAuth,proto3,oneof" json:"metrics_basic_auth,omitempty"`
MetricsCertificate *Settings_Certificate `protobuf:"bytes,65,opt,name=metrics_certificate,json=metricsCertificate,proto3,oneof" json:"metrics_certificate,omitempty"`
MetricsClientCa *string `protobuf:"bytes,66,opt,name=metrics_client_ca,json=metricsClientCa,proto3,oneof" json:"metrics_client_ca,omitempty"`
MetricsClientCaFile *string `protobuf:"bytes,67,opt,name=metrics_client_ca_file,json=metricsClientCaFile,proto3,oneof" json:"metrics_client_ca_file,omitempty"`
TracingProvider *string `protobuf:"bytes,41,opt,name=tracing_provider,json=tracingProvider,proto3,oneof" json:"tracing_provider,omitempty"`
TracingSampleRate *float64 `protobuf:"fixed64,42,opt,name=tracing_sample_rate,json=tracingSampleRate,proto3,oneof" json:"tracing_sample_rate,omitempty"`
TracingJaegerCollectorEndpoint *string `protobuf:"bytes,43,opt,name=tracing_jaeger_collector_endpoint,json=tracingJaegerCollectorEndpoint,proto3,oneof" json:"tracing_jaeger_collector_endpoint,omitempty"`
TracingJaegerAgentEndpoint *string `protobuf:"bytes,44,opt,name=tracing_jaeger_agent_endpoint,json=tracingJaegerAgentEndpoint,proto3,oneof" json:"tracing_jaeger_agent_endpoint,omitempty"`
TracingZipkinEndpoint *string `protobuf:"bytes,45,opt,name=tracing_zipkin_endpoint,json=tracingZipkinEndpoint,proto3,oneof" json:"tracing_zipkin_endpoint,omitempty"`
GrpcAddress *string `protobuf:"bytes,46,opt,name=grpc_address,json=grpcAddress,proto3,oneof" json:"grpc_address,omitempty"`
GrpcInsecure *bool `protobuf:"varint,47,opt,name=grpc_insecure,json=grpcInsecure,proto3,oneof" json:"grpc_insecure,omitempty"`
// optional string forward_auth_url = 50;
DatabrokerServiceUrls []string `protobuf:"bytes,52,rep,name=databroker_service_urls,json=databrokerServiceUrls,proto3" json:"databroker_service_urls,omitempty"`
DatabrokerInternalServiceUrl *string `protobuf:"bytes,84,opt,name=databroker_internal_service_url,json=databrokerInternalServiceUrl,proto3,oneof" json:"databroker_internal_service_url,omitempty"`
ClientCa *string `protobuf:"bytes,53,opt,name=client_ca,json=clientCa,proto3,oneof" json:"client_ca,omitempty"`
@ -1367,13 +1368,6 @@ func (x *Settings) GetGrpcInsecure() bool {
return false
}
func (x *Settings) GetForwardAuthUrl() string {
if x != nil && x.ForwardAuthUrl != nil {
return *x.ForwardAuthUrl
}
return ""
}
func (x *Settings) GetDatabrokerServiceUrls() []string {
if x != nil {
return x.DatabrokerServiceUrls
@ -1941,7 +1935,7 @@ var file_config_proto_rawDesc = []byte{
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, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9d, 0x32, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd9, 0x31, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x12, 0x2c, 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x47, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01,
@ -2116,237 +2110,233 @@ var file_config_proto_rawDesc = []byte{
0x2a, 0x52, 0x0b, 0x67, 0x72, 0x70, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01,
0x01, 0x12, 0x28, 0x0a, 0x0d, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75,
0x72, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x48, 0x2b, 0x52, 0x0c, 0x67, 0x72, 0x70, 0x63,
0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x66,
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x18,
0x32, 0x20, 0x01, 0x28, 0x09, 0x48, 0x2c, 0x52, 0x0e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
0x41, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x17, 0x64, 0x61,
0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x34, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x64, 0x61, 0x74,
0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72,
0x6c, 0x73, 0x12, 0x4a, 0x0a, 0x1f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72,
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x54, 0x20, 0x01, 0x28, 0x09, 0x48, 0x2d, 0x52, 0x1c, 0x64,
0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20,
0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x35, 0x20, 0x01, 0x28,
0x09, 0x48, 0x2e, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x88, 0x01, 0x01,
0x12, 0x29, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x09, 0x48, 0x2f, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x18, 0x4a, 0x20, 0x01, 0x28, 0x09, 0x48,
0x30, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12,
0x2b, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x5f, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x4b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x31, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x43, 0x72, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x76, 0x0a, 0x36,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x48, 0x32, 0x52, 0x31,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x18, 0x38, 0x20, 0x01, 0x28, 0x08, 0x48, 0x33, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x5f, 0x63, 0x61, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x34, 0x52, 0x0a, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x4d, 0x20,
0x01, 0x28, 0x09, 0x48, 0x35, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x45,
0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x4e,
0x20, 0x01, 0x28, 0x09, 0x48, 0x36, 0x52, 0x10, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x45, 0x61, 0x62, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x37, 0x52, 0x11, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x61, 0x62, 0x4d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x88, 0x01,
0x01, 0x12, 0x33, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x48, 0x38,
0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65,
0x64, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x18, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x51, 0x20, 0x01, 0x28, 0x09, 0x48, 0x39, 0x52, 0x15, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x61, 0x46, 0x69, 0x6c,
0x65, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x18, 0x39, 0x20, 0x01,
0x28, 0x08, 0x48, 0x3a, 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x55, 0x73,
0x65, 0x53, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x14, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61,
0x70, 0x6c, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x48, 0x3b, 0x52, 0x12, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x4d, 0x75, 0x73, 0x74, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x88,
0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64,
0x69, 0x72, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3c, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x44, 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, 0x3d, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41, 0x70,
0x70, 0x65, 0x6e, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x78, 0x66, 0x66, 0x5f, 0x6e,
0x75, 0x6d, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18,
0x46, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x3e, 0x52, 0x11, 0x78, 0x66, 0x66, 0x4e, 0x75, 0x6d, 0x54,
0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x53, 0x0a,
0x26, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x65,
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77, 0x68,
0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x44, 0x20, 0x03, 0x28, 0x09, 0x52, 0x23, 0x70,
0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x52, 0x65, 0x64, 0x69, 0x72,
0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69,
0x73, 0x74, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18,
0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d,
0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,
0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x48, 0x3f, 0x52,
0x08, 0x61, 0x75, 0x64, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x80, 0x01, 0x0a,
0x0a, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x49, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x5c, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e,
0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x54, 0x79, 0x70, 0x65, 0x48,
0x40, 0x52, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12,
0x28, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x18, 0x55, 0x20, 0x01, 0x28, 0x09, 0x48, 0x41, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72,
0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x73, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x56, 0x20, 0x01,
0x28, 0x09, 0x48, 0x42, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43,
0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d,
0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x18, 0x57, 0x20, 0x01, 0x28, 0x09, 0x48, 0x43, 0x52, 0x14, 0x64, 0x61, 0x72, 0x6b, 0x6d,
0x6f, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88,
0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x58,
0x20, 0x01, 0x28, 0x09, 0x48, 0x44, 0x52, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65,
0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01,
0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x59, 0x20,
0x01, 0x28, 0x09, 0x48, 0x45, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x88, 0x01,
0x01, 0x12, 0x24, 0x0a, 0x0b, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c,
0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x46, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f,
0x6e, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x1d, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x70,
0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x47,
0x52, 0x1a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x69,
0x72, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x88, 0x01, 0x01, 0x1a,
0x81, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12,
0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08,
0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x65, 0x72,
0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79,
0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x42, 0x79,
0x74, 0x65, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61,
0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15,
0x4a, 0x77, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x42,
0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x12, 0x0a,
0x10, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65,
0x6c, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x12, 0x0a, 0x10,
0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f,
0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f,
0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f, 0x0a,
0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x42, 0x10,
0x0a, 0x0e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65,
0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x69, 0x64, 0x6c,
0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
0x74, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x24,
0x0a, 0x22, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70,
0x61, 0x74, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x6e,
0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65,
0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b,
0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63, 0x6f,
0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x42, 0x10,
0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65,
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
0x69, 0x64, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69, 0x64, 0x70,
0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x64,
0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x21,
0x0a, 0x1f, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72,
0x6c, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42,
0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x63, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x74, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x69, 0x67,
0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65, 0x66,
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x73, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68,
0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x19,
0x0a, 0x17, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74, 0x72,
0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x16,
0x0a, 0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69,
0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e,
0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f,
0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x1a,
0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x7a, 0x69, 0x70, 0x6b, 0x69,
0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x67,
0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f,
0x67, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a,
0x11, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75,
0x72, 0x6c, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65,
0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x17, 0x64,
0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x5f, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x34, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x64, 0x61,
0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55,
0x72, 0x6c, 0x73, 0x12, 0x4a, 0x0a, 0x1f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65,
0x72, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x61, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x72, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x39, 0x0a, 0x37, 0x5f, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
0x72, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x63, 0x61, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x42, 0x17, 0x0a,
0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d,
0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x42, 0x1b,
0x0a, 0x19, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73,
0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61,
0x67, 0x69, 0x6e, 0x67, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x5f, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x42, 0x0f, 0x0a,
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, 0x17, 0x0a, 0x15, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f,
0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f,
0x64, 0x65, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x70, 0x72, 0x69,
0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x19,
0x0a, 0x17, 0x5f, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d,
0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x61,
0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x5f,
0x75, 0x72, 0x6c, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f,
0x75, 0x72, 0x6c, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x67, 0x72, 0x61, 0x70, 0x68, 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,
0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x54, 0x20, 0x01, 0x28, 0x09, 0x48, 0x2c, 0x52, 0x1c,
0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12,
0x20, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x35, 0x20, 0x01,
0x28, 0x09, 0x48, 0x2d, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x88, 0x01,
0x01, 0x12, 0x29, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x09, 0x48, 0x2e, 0x52, 0x0c, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x18, 0x4a, 0x20, 0x01, 0x28, 0x09,
0x48, 0x2f, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x6c, 0x88, 0x01, 0x01,
0x12, 0x2b, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x5f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x4b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x30, 0x52, 0x0d, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x43, 0x72, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x76, 0x0a,
0x36, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x48, 0x31, 0x52,
0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x08, 0x48, 0x32, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
0x72, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x33, 0x52, 0x0a, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x4d,
0x20, 0x01, 0x28, 0x09, 0x48, 0x34, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18,
0x4e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x35, 0x52, 0x10, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x45, 0x61, 0x62, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63,
0x5f, 0x6b, 0x65, 0x79, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x36, 0x52, 0x11, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x61, 0x62, 0x4d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x88,
0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x48,
0x37, 0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74,
0x65, 0x64, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x18, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x5f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x51, 0x20, 0x01, 0x28, 0x09, 0x48, 0x38, 0x52, 0x15, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x61, 0x46, 0x69,
0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x18, 0x39, 0x20,
0x01, 0x28, 0x08, 0x48, 0x39, 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x55,
0x73, 0x65, 0x53, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x14,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x73, 0x74,
0x61, 0x70, 0x6c, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x48, 0x3a, 0x52, 0x12, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x4d, 0x75, 0x73, 0x74, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x65,
0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x64, 0x69, 0x72, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3b, 0x52, 0x0b, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x44, 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, 0x3c, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41,
0x70, 0x70, 0x65, 0x6e, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x78, 0x66, 0x66, 0x5f,
0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73,
0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x3d, 0x52, 0x11, 0x78, 0x66, 0x66, 0x4e, 0x75, 0x6d,
0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x53,
0x0a, 0x26, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72,
0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77,
0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x44, 0x20, 0x03, 0x28, 0x09, 0x52, 0x23,
0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x52, 0x65, 0x64, 0x69,
0x72, 0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c,
0x69, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79,
0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75,
0x6d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
0x79, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x48, 0x3e,
0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x80, 0x01,
0x0a, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x49, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x5c, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x76, 0x33,
0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x54, 0x79, 0x70, 0x65,
0x48, 0x3f, 0x52, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01,
0x12, 0x28, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x18, 0x55, 0x20, 0x01, 0x28, 0x09, 0x48, 0x40, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6d, 0x61,
0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x73, 0x65,
0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x56, 0x20,
0x01, 0x28, 0x09, 0x48, 0x41, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16, 0x64, 0x61, 0x72, 0x6b,
0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x18, 0x57, 0x20, 0x01, 0x28, 0x09, 0x48, 0x42, 0x52, 0x14, 0x64, 0x61, 0x72, 0x6b,
0x6d, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f,
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18,
0x58, 0x20, 0x01, 0x28, 0x09, 0x48, 0x43, 0x52, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64,
0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88,
0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x59,
0x20, 0x01, 0x28, 0x09, 0x48, 0x44, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x88,
0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72,
0x6c, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x45, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x69, 0x63,
0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x1d, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f,
0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x09, 0x48,
0x46, 0x52, 0x1a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46,
0x69, 0x72, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x88, 0x01, 0x01,
0x1a, 0x81, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x0a,
0x08, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74,
0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x65,
0x72, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x42,
0x79, 0x74, 0x65, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50,
0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a,
0x15, 0x4a, 0x77, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67,
0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x12,
0x0a, 0x10, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76,
0x65, 0x6c, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65,
0x63, 0x72, 0x65, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x12, 0x0a,
0x10, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70,
0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70,
0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f,
0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x42,
0x10, 0x0a, 0x0e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74,
0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x69, 0x64,
0x6c, 0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42,
0x24, 0x0a, 0x22, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65,
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f,
0x70, 0x61, 0x74, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f,
0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f,
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f,
0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63,
0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x42,
0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72,
0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x5f, 0x69, 0x64, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69, 0x64,
0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69,
0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42,
0x21, 0x0a, 0x1f, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75,
0x72, 0x6c, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x63,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x74, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x69,
0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65,
0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
0x63, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6d,
0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74,
0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42,
0x19, 0x0a, 0x17, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74,
0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42,
0x16, 0x0a, 0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x74, 0x72, 0x61, 0x63,
0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65,
0x63, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x20, 0x0a,
0x1e, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72,
0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42,
0x1a, 0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x7a, 0x69, 0x70, 0x6b,
0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f,
0x67, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e,
0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x22,
0x0a, 0x20, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75,
0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61,
0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66,
0x69, 0x6c, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63,
0x72, 0x6c, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72,
0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x39, 0x0a, 0x37, 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65,
0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x42, 0x0e,
0x0a, 0x0c, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x11,
0x0a, 0x0f, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65,
0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x6b,
0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f,
0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67,
0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75,
0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x42, 0x0f, 0x0a, 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, 0x17,
0x0a, 0x15, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74,
0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x75, 0x64, 0x69,
0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e,
0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x64,
0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f,
0x64, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x42,
0x0e, 0x0a, 0x0c, 0x5f, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x42,
0x20, 0x0a, 0x1e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70,
0x68, 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 (

View file

@ -192,7 +192,7 @@ message Settings {
optional string tracing_zipkin_endpoint = 45;
optional string grpc_address = 46;
optional bool grpc_insecure = 47;
optional string forward_auth_url = 50;
// optional string forward_auth_url = 50;
repeated string databroker_service_urls = 52;
optional string databroker_internal_service_url = 84;
optional string client_ca = 53;

View file

@ -841,6 +841,7 @@ type SyncLatestResponse struct {
unknownFields protoimpl.UnknownFields
// Types that are assignable to Response:
//
// *SyncLatestResponse_Record
// *SyncLatestResponse_Versions
Response isSyncLatestResponse_Response `protobuf_oneof:"response"`

View file

@ -332,6 +332,7 @@ type Type struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
// Types that are assignable to Specifier:
//
// *Type_Webauthn
Specifier isType_Specifier `protobuf_oneof:"specifier"`
}
@ -521,6 +522,7 @@ type Credential struct {
EnrollmentId string `protobuf:"bytes,3,opt,name=enrollment_id,json=enrollmentId,proto3" json:"enrollment_id,omitempty"`
UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
// Types that are assignable to Specifier:
//
// *Credential_Webauthn
Specifier isCredential_Specifier `protobuf_oneof:"specifier"`
}

View file

@ -315,6 +315,7 @@ type Session_DeviceCredential struct {
TypeId string `protobuf:"bytes,1,opt,name=type_id,json=typeId,proto3" json:"type_id,omitempty"`
// Types that are assignable to Credential:
//
// *Session_DeviceCredential_Unavailable
// *Session_DeviceCredential_Id
Credential isSession_DeviceCredential_Credential `protobuf_oneof:"credential"`

View file

@ -1,142 +0,0 @@
package proxy
import (
"errors"
"fmt"
"net/http"
"net/url"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/urlutil"
)
// registerFwdAuthHandlers returns a set of handlers that support using pomerium
// as a "forward-auth" provider with other reverse proxies like nginx, traefik.
//
// see : https://www.pomerium.com/docs/reference/forward-auth
func (p *Proxy) registerFwdAuthHandlers() http.Handler {
r := httputil.NewRouter()
// NGNIX's forward-auth capabilities are split across two settings:
// `auth-url` and `auth-signin` which correspond to `verify` and `auth-url`
//
// NOTE: Route order matters here which makes the request flow confusing
// to reason about so each step has a postfix order step.
// nginx 3: save the returned session post authenticate flow
r.Handle("/verify", httputil.HandlerFunc(p.nginxCallback)).
Queries(urlutil.QueryForwardAuthURI, "{uri}",
urlutil.QuerySessionEncrypted, "",
urlutil.QueryRedirectURI, "")
// nginx 1: verify, fronted by ext_authz
r.Handle("/verify", httputil.HandlerFunc(p.allowUpstream)).
Queries(urlutil.QueryForwardAuthURI, "{uri}")
// nginx 4: redirect the user back to their originally requested location.
r.Handle("/", httputil.HandlerFunc(p.nginxPostCallbackRedirect)).
Queries(urlutil.QueryForwardAuthURI, "{uri}",
urlutil.QuerySessionEncrypted, "",
urlutil.QueryRedirectURI, "")
// traefik 2: save the returned session post authenticate flow
r.Handle("/", httputil.HandlerFunc(p.forwardedURIHeaderCallback)).
HeadersRegexp(httputil.HeaderForwardedURI, urlutil.QuerySessionEncrypted)
r.Handle("/", httputil.HandlerFunc(p.startAuthN)).
Queries(urlutil.QueryForwardAuthURI, "{uri}")
// otherwise, send a 200 OK for any other route.
// these routes do _not_ enforce authZ, they are helper routes.
r.NotFoundHandler = httputil.HandlerFunc(p.allowUpstream)
return r
}
// nginxPostCallbackRedirect redirects the user to their original destination
// in order to drop the authenticate related query params
func (p *Proxy) nginxPostCallbackRedirect(w http.ResponseWriter, r *http.Request) error {
u, err := url.Parse(r.FormValue(urlutil.QueryRedirectURI))
if err != nil {
return httputil.NewError(http.StatusBadRequest, err)
}
httputil.Redirect(w, r, u.String(), http.StatusFound)
return nil
}
// nginxCallback saves the returned session post callback and then returns an
// unauthorized status in order to restart the request flow process. Strangely
// we need to throw a 401 after saving the session to redirect the user
// to their originally desired location.
func (p *Proxy) nginxCallback(w http.ResponseWriter, r *http.Request) error {
encryptedSession := r.FormValue(urlutil.QuerySessionEncrypted)
if _, err := p.saveCallbackSession(w, r, encryptedSession); err != nil {
return httputil.NewError(http.StatusBadRequest, err)
}
return httputil.NewError(http.StatusUnauthorized, errors.New("mock error to restart redirect flow"))
}
// forwardedURIHeaderCallback handles the post-authentication callback from
// forwarding proxies that support the `X-Forwarded-Uri`.
func (p *Proxy) forwardedURIHeaderCallback(w http.ResponseWriter, r *http.Request) error {
forwardedURL, err := url.Parse(r.Header.Get(httputil.HeaderForwardedURI))
if err != nil {
return httputil.NewError(http.StatusBadRequest, err)
}
q := forwardedURL.Query()
redirectURLString := q.Get(urlutil.QueryRedirectURI)
encryptedSession := q.Get(urlutil.QuerySessionEncrypted)
if _, err := p.saveCallbackSession(w, r, encryptedSession); err != nil {
return httputil.NewError(http.StatusBadRequest, err)
}
httputil.Redirect(w, r, redirectURLString, http.StatusFound)
return nil
}
// allowUpstream will return status 200 (OK) unless auth_status is set to forbidden.
// This handler is expected to be behind a routed protected by envoy's control plane (ext_authz).
func (p *Proxy) allowUpstream(w http.ResponseWriter, r *http.Request) error {
if status := r.FormValue("auth_status"); status == fmt.Sprint(http.StatusForbidden) {
return httputil.NewError(http.StatusForbidden, errors.New(http.StatusText(http.StatusForbidden)))
}
// in forward-auth configuration we want to treat our request headers as response headers
// so that they can be forwarded by the fronting proxy, if desired
for k, vs := range r.Header {
for _, v := range vs {
w.Header().Set(k, v)
}
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, http.StatusText(http.StatusOK))
return nil
}
// startAuthN redirects an unauthenticated user to start forward-auth
// authentication flow
func (p *Proxy) startAuthN(w http.ResponseWriter, r *http.Request) error {
state := p.state.Load()
uriString := r.FormValue(urlutil.QueryForwardAuthURI)
if uriString == "" {
uriString = "https://" + // always use HTTPS for external urls
r.Header.Get(httputil.HeaderForwardedHost) +
r.Header.Get(httputil.HeaderForwardedURI)
}
uri, err := urlutil.ParseAndValidateURL(uriString)
if err != nil {
return httputil.NewError(http.StatusBadRequest, err)
}
// add any non-empty existing path from the forwarded URI
if xfu := r.Header.Get(httputil.HeaderForwardedURI); xfu != "" && xfu != "/" {
uri.Path = xfu
}
authN := *state.authenticateSigninURL
q := authN.Query()
q.Set(urlutil.QueryCallbackURI, uri.String())
q.Set(urlutil.QueryRedirectURI, uri.String()) // final destination
q.Set(urlutil.QueryForwardAuth, urlutil.StripPort(r.Host)) // add fwd auth to trusted audience
authN.RawQuery = q.Encode()
httputil.Redirect(w, r, urlutil.NewSignedURL(state.sharedKey, &authN).String(), http.StatusFound)
return nil
}

View file

@ -1,137 +0,0 @@
package proxy
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"testing"
envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
"github.com/google/go-cmp/cmp"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/encoding"
"github.com/pomerium/pomerium/internal/encoding/jws"
"github.com/pomerium/pomerium/internal/encoding/mock"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/sessions"
mstore "github.com/pomerium/pomerium/internal/sessions/mock"
"github.com/pomerium/pomerium/internal/urlutil"
)
type mockCheckClient struct {
response *envoy_service_auth_v2.CheckResponse
err error
}
func (m *mockCheckClient) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRequest, opts ...grpc.CallOption) (*envoy_service_auth_v2.CheckResponse, error) {
return m.response, m.err
}
func TestProxy_ForwardAuth(t *testing.T) {
ctx := context.Background()
t.Parallel()
allowClient := &mockCheckClient{
response: &envoy_service_auth_v2.CheckResponse{
Status: &status.Status{Code: int32(codes.OK), Message: "OK"},
HttpResponse: &envoy_service_auth_v2.CheckResponse_OkResponse{},
},
}
opts := testOptions(t)
tests := []struct {
name string
options *config.Options
ctxError error
method string
headers map[string]string
qp map[string]string
requestURI string
verifyURI string
cipher encoding.MarshalUnmarshaler
sessionStore sessions.SessionStore
authorizer envoy_service_auth_v2.AuthorizationClient
wantStatus int
wantBody string
}{
{"good verify only, no redirect", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/verify", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusOK, ""},
{"bad empty domain uri", opts, nil, http.MethodGet, nil, map[string]string{"uri": ""}, "https://some.domain.example/", "", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
{"bad naked domain uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", "a.naked.domain", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
{"bad empty verification uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", " ", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
// traefik
{"good traefik callback", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusFound, ""},
{"bad traefik callback bad session", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString + "garbage"}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, ""},
{"bad traefik callback bad url", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: urlutil.QuerySessionEncrypted + ""}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, ""},
{"good traefik verify uri from headers", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedProto: "https", httputil.HeaderForwardedHost: "some.domain.example:8080"}, nil, "https://some.domain.example/", "", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusOK, ""},
{"good traefik verify uri from insecure headers", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedProto: "http", httputil.HeaderForwardedHost: "some.domain.example:8080"}, nil, "https://some.domain.example/", "", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusOK, ""},
// // nginx
{"good nginx callback redirect", opts, nil, http.MethodGet, nil, map[string]string{urlutil.QueryRedirectURI: "https://some.domain.example/", urlutil.QuerySessionEncrypted: goodEncryptionString}, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusFound, ""},
{"good nginx callback set session okay but return unauthorized", opts, nil, http.MethodGet, nil, map[string]string{urlutil.QueryRedirectURI: "https://some.domain.example/", urlutil.QuerySessionEncrypted: goodEncryptionString}, "https://some.domain.example/verify", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusUnauthorized, ""},
{"bad nginx callback failed to set session", opts, nil, http.MethodGet, nil, map[string]string{urlutil.QueryRedirectURI: "https://some.domain.example/", urlutil.QuerySessionEncrypted: goodEncryptionString + "nope"}, "https://some.domain.example/verify", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p, err := New(&config.Config{Options: tt.options})
if err != nil {
t.Fatal(err)
}
p.OnConfigChange(ctx, &config.Config{Options: tt.options})
state := p.state.Load()
state.sessionStore = tt.sessionStore
signer, err := jws.NewHS256Signer(nil)
if err != nil {
t.Fatal(err)
}
state.encoder = signer
uri, err := url.Parse(tt.requestURI)
if err != nil {
t.Fatal(err)
}
queryString := uri.Query()
for k, v := range tt.qp {
queryString.Set(k, v)
}
if tt.verifyURI != "" {
queryString.Set("uri", tt.verifyURI)
}
uri.RawQuery = queryString.Encode()
r := httptest.NewRequest(tt.method, uri.String(), nil)
ss, _ := tt.sessionStore.LoadSession(r)
ctx := r.Context()
ctx = sessions.NewContext(ctx, ss, tt.ctxError)
r = r.WithContext(ctx)
r.Header.Set("Accept", "application/json")
if len(tt.headers) != 0 {
for k, v := range tt.headers {
r.Header.Set(k, v)
}
}
w := httptest.NewRecorder()
router := p.registerFwdAuthHandlers()
router.ServeHTTP(w, r)
if status := w.Code; status != tt.wantStatus {
t.Errorf("status code: got %v want %v in %s", status, tt.wantStatus, tt.name)
t.Errorf("\n%+v", w.Body.String())
}
if tt.wantBody != "" {
body := w.Body.String()
if diff := cmp.Diff(body, tt.wantBody); diff != "" {
t.Errorf("wrong body\n%s", diff)
}
}
})
}
}

View file

@ -4,7 +4,6 @@ import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
@ -35,7 +34,7 @@ func TestProxy_RobotsTxt(t *testing.T) {
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}
expected := fmt.Sprintf("User-agent: *\nDisallow: /")
expected := "User-agent: *\nDisallow: /"
if rr.Body.String() != expected {
t.Errorf("handler returned wrong body: got %v want %v", rr.Body.String(), expected)
}

View file

@ -116,16 +116,6 @@ func (p *Proxy) setHandlers(opts *config.Options) error {
// dashboard handlers are registered to all routes
r = p.registerDashboardHandlers(r)
forwardAuthURL, err := opts.GetForwardAuthURL()
if err != nil {
return err
}
if forwardAuthURL != nil {
// if a forward auth endpoint is set, register its handlers
h := r.Host(forwardAuthURL.Hostname()).Subrouter()
h.PathPrefix("/").Handler(p.registerFwdAuthHandlers())
}
p.currentRouter.Store(r)
return nil
}

View file

@ -158,8 +158,7 @@ func Test_UpdateOptions(t *testing.T) {
corsPreflight.Policies = []config.Policy{{To: toFoo, From: "http://bar.example", CORSAllowPreflight: true}}
disableAuth := testOptions(t)
disableAuth.Policies = []config.Policy{{To: toFoo, From: "http://bar.example", AllowPublicUnauthenticatedAccess: true}}
fwdAuth := testOptions(t)
fwdAuth.ForwardAuthURLString = "https://corp.example.example"
reqHeaders := testOptions(t)
reqHeaders.Policies = []config.Policy{{To: toFoo, From: "http://bar.example", SetRequestHeaders: map[string]string{"x": "y"}}}
preserveHostHeader := testOptions(t)
@ -185,7 +184,6 @@ func Test_UpdateOptions(t *testing.T) {
{"no websockets, custom timeout", good, customTimeout, "https://corp.example.example", false, true},
{"enable cors preflight", good, corsPreflight, "https://corp.example.example", false, true},
{"disable auth", good, disableAuth, "https://corp.example.example", false, true},
{"enable forward auth", good, fwdAuth, "https://corp.example.example", false, true},
{"set request headers", good, reqHeaders, "https://corp.example.example", false, true},
{"preserve host headers", preserveHostHeader, preserveHostHeader, "https://corp.example.example", false, true},
}