authorize: add client mTLS support (#751)

* authorize: add client mtls support

* authorize: better error messages for envoy

* switch from function to input

* add TrustedCa to envoy config so that users are prompted for the correct client certificate

* update documentation

* fix invalid ClientCAFile

* regenerate cache protobuf

* avoid recursion, add test

* move comment line

* use http.StatusOK

* various fixes
This commit is contained in:
Caleb Doxsey 2020-05-21 16:01:07 -06:00 committed by GitHub
parent 3f1faf2e9e
commit e4832cb4ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 995 additions and 279 deletions

View file

@ -2,10 +2,14 @@
// if a given request should be authorized (AuthZ). // if a given request should be authorized (AuthZ).
package authorize package authorize
//go:generate ../scripts/protoc -I ../internal/grpc/authorize/ --go_out=plugins=grpc:../internal/grpc/authorize/ ../internal/grpc/authorize/authorize.proto
import ( import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"html/template"
"io/ioutil"
"sync/atomic" "sync/atomic"
"github.com/pomerium/pomerium/authorize/evaluator" "github.com/pomerium/pomerium/authorize/evaluator"
@ -14,6 +18,7 @@ import (
"github.com/pomerium/pomerium/internal/cryptutil" "github.com/pomerium/pomerium/internal/cryptutil"
"github.com/pomerium/pomerium/internal/encoding" "github.com/pomerium/pomerium/internal/encoding"
"github.com/pomerium/pomerium/internal/encoding/jws" "github.com/pomerium/pomerium/internal/encoding/jws"
"github.com/pomerium/pomerium/internal/frontend"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry/metrics" "github.com/pomerium/pomerium/internal/telemetry/metrics"
"github.com/pomerium/pomerium/internal/telemetry/trace" "github.com/pomerium/pomerium/internal/telemetry/trace"
@ -51,6 +56,7 @@ type Authorize struct {
currentOptions atomicOptions currentOptions atomicOptions
currentEncoder atomicMarshalUnmarshaler currentEncoder atomicMarshalUnmarshaler
templates *template.Template
} }
// New validates and creates a new Authorize service from a set of config options. // New validates and creates a new Authorize service from a set of config options.
@ -58,7 +64,9 @@ func New(opts config.Options) (*Authorize, error) {
if err := validateOptions(opts); err != nil { if err := validateOptions(opts); err != nil {
return nil, fmt.Errorf("authorize: bad options: %w", err) return nil, fmt.Errorf("authorize: bad options: %w", err)
} }
var a Authorize a := Authorize{
templates: template.Must(frontend.NewTemplates()),
}
var host string var host string
if opts.AuthenticateURL != nil { if opts.AuthenticateURL != nil {
@ -117,12 +125,28 @@ func newPolicyEvaluator(opts *config.Options) (evaluator.Evaluator, error) {
jwk.Key = keyBytes jwk.Key = keyBytes
} }
var clientCA string
if opts.ClientCA != "" {
bs, err := base64.StdEncoding.DecodeString(opts.ClientCA)
if err != nil {
return nil, fmt.Errorf("authorize: invalid client ca: %w", err)
}
clientCA = string(bs)
} else if opts.ClientCAFile != "" {
bs, err := ioutil.ReadFile(opts.ClientCAFile)
if err != nil {
return nil, fmt.Errorf("authorize: invalid client ca file: %w", err)
}
clientCA = string(bs)
}
data := map[string]interface{}{ data := map[string]interface{}{
"shared_key": opts.SharedKey, "shared_key": opts.SharedKey,
"route_policies": opts.Policies, "route_policies": opts.Policies,
"admins": opts.Administrators, "admins": opts.Administrators,
"signing_key": jwk, "signing_key": jwk,
"authenticate_url": opts.AuthenticateURLString, "authenticate_url": opts.AuthenticateURLString,
"client_ca": clientCA,
} }
return opa.New(ctx, &opa.Options{Data: data}) return opa.New(ctx, &opa.Options{Data: data})

106
authorize/errors.go Normal file
View file

@ -0,0 +1,106 @@
package authorize
import (
"bytes"
"net/http"
"strings"
envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
envoy_type "github.com/envoyproxy/go-control-plane/envoy/type"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/log"
)
func (a *Authorize) deniedResponse(in *envoy_service_auth_v2.CheckRequest,
code int32, reason string, headers map[string]string) *envoy_service_auth_v2.CheckResponse {
returnHTMLError := true
inHeaders := in.GetAttributes().GetRequest().GetHttp().GetHeaders()
if inHeaders != nil {
returnHTMLError = strings.Contains(inHeaders["accept"], "text/html")
}
if returnHTMLError {
return a.htmlDeniedResponse(code, reason, headers)
}
return a.plainTextDeniedResponse(code, reason, headers)
}
func (a *Authorize) htmlDeniedResponse(code int32, reason string, headers map[string]string) *envoy_service_auth_v2.CheckResponse {
var details string
switch code {
case httputil.StatusInvalidClientCertificate:
details = "a valid client certificate is required to access this page"
case http.StatusForbidden:
details = "access to this page is forbidden"
default:
details = reason
}
var buf bytes.Buffer
err := a.templates.ExecuteTemplate(&buf, "error.html", map[string]interface{}{
"Status": code,
"StatusText": reason,
"CanDebug": code/100 == 4,
"Error": details,
})
if err != nil {
buf.WriteString(reason)
log.Error().Err(err).Msg("error executing error template")
}
envoyHeaders := []*envoy_api_v2_core.HeaderValueOption{
mkHeader("Content-Type", "text/html"),
}
for k, v := range headers {
envoyHeaders = append(envoyHeaders, mkHeader(k, v))
}
return &envoy_service_auth_v2.CheckResponse{
Status: &status.Status{Code: int32(codes.PermissionDenied), Message: "Access Denied"},
HttpResponse: &envoy_service_auth_v2.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v2.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode(code),
},
Headers: envoyHeaders,
Body: buf.String(),
},
},
}
}
func (a *Authorize) plainTextDeniedResponse(code int32, reason string, headers map[string]string) *envoy_service_auth_v2.CheckResponse {
envoyHeaders := []*envoy_api_v2_core.HeaderValueOption{
mkHeader("Content-Type", "text/plain"),
}
for k, v := range headers {
envoyHeaders = append(envoyHeaders, mkHeader(k, v))
}
return &envoy_service_auth_v2.CheckResponse{
Status: &status.Status{Code: int32(codes.PermissionDenied), Message: "Access Denied"},
HttpResponse: &envoy_service_auth_v2.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v2.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode(code),
},
Headers: envoyHeaders,
Body: reason,
},
},
}
}
func mkHeader(k, v string) *envoy_api_v2_core.HeaderValueOption {
return &envoy_api_v2_core.HeaderValueOption{
Header: &envoy_api_v2_core.HeaderValue{
Key: k,
Value: v,
},
}
}

View file

@ -10,7 +10,7 @@ import (
// Evaluator specifies the interface for a policy engine. // Evaluator specifies the interface for a policy engine.
type Evaluator interface { type Evaluator interface {
IsAuthorized(ctx context.Context, input interface{}) (*pb.IsAuthorizedReply, error) IsAuthorized(ctx context.Context, req *Request) (*pb.IsAuthorizedReply, error)
PutData(ctx context.Context, data map[string]interface{}) error PutData(ctx context.Context, data map[string]interface{}) error
} }
@ -44,6 +44,11 @@ type Request struct {
// It is an error to set this field in an HTTP client request. // It is an error to set this field in an HTTP client request.
RequestURI string `json:"request_uri,omitempty"` RequestURI string `json:"request_uri,omitempty"`
// Connection context
//
// ClientCertificate is the PEM-encoded public certificate used for the user's TLS connection.
ClientCertificate string `json:"client_certificate"`
// Device context // Device context
// //
// todo(bdd): Use the peer TLS certificate to bind device state with a request // todo(bdd): Use the peer TLS certificate to bind device state with a request

View file

@ -0,0 +1,58 @@
package opa
import (
"crypto/x509"
"encoding/pem"
"fmt"
lru "github.com/hashicorp/golang-lru"
)
var isValidClientCertificateCache, _ = lru.New2Q(100)
func isValidClientCertificate(ca, cert string) (bool, error) {
// when ca is the empty string, client certificates are always accepted
if ca == "" {
return true, nil
}
// when cert is the empty string, no client certificate was supplied
if cert == "" {
return false, nil
}
cacheKey := [2]string{ca, cert}
value, ok := isValidClientCertificateCache.Get(cacheKey)
if ok {
return value.(bool), nil
}
roots := x509.NewCertPool()
roots.AppendCertsFromPEM([]byte(ca))
xcert, err := parseCertificate(cert)
if err != nil {
return false, err
}
_, verifyErr := xcert.Verify(x509.VerifyOptions{
Roots: roots,
})
valid := verifyErr == nil
isValidClientCertificateCache.Add(cacheKey, valid)
return valid, nil
}
func parseCertificate(pemStr string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(pemStr))
if block == nil {
return nil, fmt.Errorf("invalid certificate")
}
if block.Type != "CERTIFICATE" {
return nil, fmt.Errorf("unknown PEM type: %s", block.Type)
}
return x509.ParseCertificate(block.Bytes)
}

View file

@ -0,0 +1,122 @@
package opa
import (
"testing"
"github.com/stretchr/testify/assert"
)
const (
testCA = `
-----BEGIN CERTIFICATE-----
MIIEtjCCAx6gAwIBAgIRAJFkXxMjoQzoojykk6CiiGkwDQYJKoZIhvcNAQELBQAw
czEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSQwIgYDVQQLDBtjYWxl
YkBwb3Atb3MgKENhbGViIERveHNleSkxKzApBgNVBAMMIm1rY2VydCBjYWxlYkBw
b3Atb3MgKENhbGViIERveHNleSkwHhcNMjAwNDI0MTY1MzEwWhcNMzAwNDI0MTY1
MzEwWjBzMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExJDAiBgNVBAsM
G2NhbGViQHBvcC1vcyAoQ2FsZWIgRG94c2V5KTErMCkGA1UEAwwibWtjZXJ0IGNh
bGViQHBvcC1vcyAoQ2FsZWIgRG94c2V5KTCCAaIwDQYJKoZIhvcNAQEBBQADggGP
ADCCAYoCggGBAL2QSyQGjaGD97K7HSExJfMcuyEoh+ewAkPZ/HZR4n12zwAn1sLK
RqusKSfMe8qG6KgsojXrJ9AXEkD7x3bmK5j/4M/lwlNGulg+k5MSu3leoLpOZwfX
JQTu+HDzWubu5cjy7taHyeZc35VbOBWEaDJgVxmJvE9TJIOr8POZ7DD/rlkbgQas
s6G/8cg2mRX0Rh3O20/1bvi9Uen/kraBgGMOyG5MfuiiTl3KsrGST848Q+jiSbu3
5F5MAzdO4tlR6kqEZk/Igog6OPkTb82vMli/R+mR37JYncQcj0WNYS4PkfjofVpb
FwrHtfdkVYJ9T2yNvQnJVu6MF9fhj9FqWQbsdbYKlUDow5KwI+BxmCAmGwgzmCOy
ONkglj76fPKFkoF4s+DSFocbAwhdazaViAcCB+x6yohOUjgG7H9NJo0MasPHuqUO
8d56Bf0BTXfNX6nOgYYisrOoEATCbs729vHMaQ/7pG2zf9dnEuw95gZTSr9Rv3dx
2NjmM6+tNOMCzwIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgw
BgEB/wIBADAdBgNVHQ4EFgQUShofXNkcXh2q4wnnWZ2bco24XEQwDQYJKoZIhvcN
AQELBQADggGBAJQzfmr84xtvoUgnq8T4ND0Q166dlnbDnASRFhbmyZcxzvDJsPs4
N45HbIg0xOsXOaBaE+jTSV4GmZ/vtyP8WbQrhabL2zpnjnLF1d9B0qx/RlIzoDEa
e/0zc0R6RAd64/aE/jHNDhfTNXD/NmnI25RqgnsZXXXRVMTl+PzQ1A8XQghZVWHN
vbyFFd3GE5Qs+vxMzwKCqp6f3MI8KyI2aM4hZZ+zULdEuSw0hWzMOkeZY6LC0flW
/rpkT+GLA3uZ357iehSISLqnkIozw92ldov5oZDthoy3i1I6gIDkngk7BGKr42pD
L2sWi1MEEIhymy4K1DnRkGre3mqzus2y/nE4ruuJlctq6QXcCSnko717vukVtoE8
o5SkW4usivU8yZeBLt56sySRyCpe/T1XAFTQZ5Q4S5ssGmNpOLS9Aa5iOUz9/62S
uvjFyvOEE3yqd/d3py8qm6olcjaMooVA8j5G+QF/UiH951azGIez6/Ui1lg1m0T6
+YLkPqNIt0o9dQ==
-----END CERTIFICATE-----
`
testValidCert = `
-----BEGIN CERTIFICATE-----
MIIESDCCArCgAwIBAgIQG/h9GflpINqLLv4Tde9+STANBgkqhkiG9w0BAQsFADBz
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExJDAiBgNVBAsMG2NhbGVi
QHBvcC1vcyAoQ2FsZWIgRG94c2V5KTErMCkGA1UEAwwibWtjZXJ0IGNhbGViQHBv
cC1vcyAoQ2FsZWIgRG94c2V5KTAeFw0xOTA2MDEwMDAwMDBaFw0zMDA1MjAyMDM4
NDRaME8xJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEk
MCIGA1UECwwbY2FsZWJAcG9wLW9zIChDYWxlYiBEb3hzZXkpMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ouz2dlXHALdxiLcLwAvxg02CN/Jdcrmyyzm
bzKHqIpknotZSlbPgE/mp5wMwIoyMqFIEm3IzXFEf3cjFYYG4b6wp4zlFrx7jCOa
vhEHpH3yM71xt1I/BME6VrmX7sRKO90dwpTxCOadx9aGEn1AlHuPfhMMm/WTLynD
d5hbsHKp7eZMYHvQnferTelq5NnBySBP/HaAtF76qTSQzHev5K/cgioDZAaM0dnP
bicl0Zay+f5INrDr9XtQo/FHwGI/YLMW5TWXYmHjYmdD8s4Tg/KUoRMgJp4mlkkF
9t1pwArbNFU/4wQWPbpWBLh1gcnQxojSZ3a6aI+V+REDzV/PVQIDAQABo3wwejAO
BgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwG
A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUShofXNkcXh2q4wnnWZ2bco24XEQwGgYD
VR0RBBMwEYIPZXhhbXBsZS1zdWJqZWN0MA0GCSqGSIb3DQEBCwUAA4IBgQC78S2n
6jcKfWbm24g/U5tkWiBVnBk1jphH7Ct69Lw2JNstGLtNs4AiE9lKmXDQ82MiAFYg
gaeiHRhTebkOTF9Kx3Jwq7bwhhzONqPp5a0SkY4EWjZ7c5k/fZc8DkrRE71hOgMf
rFbRBZCywBVtGbXIA1uMsCijTe4sQF1ZA918NmfjhpIhRHljQJM16RJ753s+0CZ8
WomOW4JrtjJefRuV97PRADvRNQbtZYelnoTfbp1afGhbQpKjyylCDGlpJS4mGrSA
lPaRVhEB+wI8gA3lzpa6adXsc1yueZ19++dxQNYxAawCMQNjjxy3aLWzy8aPWxxq
Qo/Q9rqjre3SpJfARLOV9ezQNbqsXvJW+5DcoG5dx8s6jAhMusNjUHpf6oVgnv65
3Bvl124bZyf9q4lW9g8pvZkrgQ3Fx2IahqhXhyF5zrqf2r9+1l0fXocIUP2GQ+Fr
b9j9bWWhov5aidEjPwpFeTmzcGqCWQBEA4H+yo/4YaIN0sOfE2yaAmc3gcU=
-----END CERTIFICATE-----
`
testUnsignedCert = `
-----BEGIN CERTIFICATE-----
MIIESTCCArGgAwIBAgIRAIE9860UHBIVofXB5cu/aWAwDQYJKoZIhvcNAQELBQAw
czEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSQwIgYDVQQLDBtjYWxl
YkBwb3Atb3MgKENhbGViIERveHNleSkxKzApBgNVBAMMIm1rY2VydCBjYWxlYkBw
b3Atb3MgKENhbGViIERveHNleSkwHhcNMTkwNjAxMDAwMDAwWhcNMzAwNTIwMjIw
NDAxWjBPMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUx
JDAiBgNVBAsMG2NhbGViQHBvcC1vcyAoQ2FsZWIgRG94c2V5KTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKPgWHAJ58p7ZZ6MHA6QHA9rQQWKSvYbN9zz
fCCURqHFbQHCCJs2D39XPioo9EMZcD6J7ldwEOJsdSNw3+dzBCvIl7wP6fqtbo/3
SNgRaLAB+Mb4S8oek6P6zHkjuOXzodhCZjLO7oxY9pjGREy6hC/SjylJFgw9mKEG
SYmsyCqeP5BfW9DghRgd5uJe0HtwlBZLPS91Mk5whn7YOxnWslS/REwZdd12s3DI
WQdmvGhMakIAiMKmx+LX9qS3Ua2gUArHnSFXcOAg9iK+MM68T1KsQTCYnRZVK4v5
Na4qEjiPhmkzzEExZa787ClL6UXfoXB+jXy2sXu0CDD4tv2D7R8CAwEAAaN8MHow
DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAM
BgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFH8wenPOF2tE2EIksItmlkWfgEMkMBoG
A1UdEQQTMBGCD2ludmFsaWQtc3ViamVjdDANBgkqhkiG9w0BAQsFAAOCAYEAJCdl
c6J/x/UY6vEDzplwR8iZ5s7dyKKF7bwNdjEvBREgkTY6GmwDC9HOmWWPs7vENqEX
jUwHEK+v7A7AUIS4WeJrJgogzEDPI7ZlVtzQNviqMavzk/I1Us00WYtMQQFb1Sgz
xIRskug5wH6vPcR4XbCftx6NP9UFG8pJLPTJ67ZUaTP23ccsToMM/Dd17LFrtleE
9xAvdqA54vcBiJ99uts+xWlQznjIgdauNC6sOmL3JAflyj6aBy+Dcos9R35ERIXz
3rRl25yXjtidPDo8YxmtHs+Ijw4R3iJ44NCcc/+LfACYUcua0cBF2Ixk2JrFYx8n
wwRJukrHXI+RFBmSOlUripyyJH92H5vXvj8lO5wM8wVVVe8anr5TOvxFOAjNC5a3
vJByvJQTUEkx8rT7zZi8eSQJHP3Eoqr9g4ajqIU22yrCxiiQXpZLJ4JFQQEgyD9A
Y+E5W+FKfIBv9yvdNBYZsL6IZ0Yh1ctKwB5gnajO8+swx5BeaCIbBrCtOBSB
-----END CERTIFICATE-----
`
)
func Test_isValidClientCertificate(t *testing.T) {
t.Run("no ca", func(t *testing.T) {
valid, err := isValidClientCertificate("", "WHATEVER!")
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("no cert", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "")
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("valid cert", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, testValidCert)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("unsigned cert", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, testUnsignedCert)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("not a cert", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "WHATEVER!")
assert.Error(t, err, "should return an error")
assert.False(t, valid, "should return false")
})
}

View file

@ -1,4 +1,5 @@
//go:generate statik -src=./policy -include=*.rego -ns rego -p policy //go:generate go run github.com/rakyll/statik -src=./policy -include=*.rego -ns rego -p policy
//go:generate go fmt ./policy/statik.go
// Package opa implements the policy evaluator interface to make authorization // Package opa implements the policy evaluator interface to make authorization
// decisions. // decisions.
@ -6,9 +7,11 @@ package opa
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"strconv"
"sync" "sync"
"github.com/open-policy-agent/opa/rego" "github.com/open-policy-agent/opa/rego"
@ -37,6 +40,7 @@ type PolicyEvaluator struct {
mu sync.RWMutex mu sync.RWMutex
store storage.Store store storage.Store
isAuthorized rego.PreparedEvalQuery isAuthorized rego.PreparedEvalQuery
clientCA string
} }
// Options represent OPA's evaluator configurations. // Options represent OPA's evaluator configurations.
@ -96,10 +100,10 @@ func (pe *PolicyEvaluator) UpdatePolicy(ctx context.Context, authz string) error
} }
// IsAuthorized determines if a given request input is authorized. // IsAuthorized determines if a given request input is authorized.
func (pe *PolicyEvaluator) IsAuthorized(ctx context.Context, input interface{}) (*pb.IsAuthorizedReply, error) { func (pe *PolicyEvaluator) IsAuthorized(ctx context.Context, req *evaluator.Request) (*pb.IsAuthorizedReply, error) {
ctx, span := trace.StartSpan(ctx, "authorize.evaluator.opa.IsAuthorized") ctx, span := trace.StartSpan(ctx, "authorize.evaluator.opa.IsAuthorized")
defer span.End() defer span.End()
return pe.runBoolQuery(ctx, input, pe.isAuthorized) return pe.runBoolQuery(ctx, req, pe.isAuthorized)
} }
// PutData adds (or replaces if the mapping key is the same) contextual data // PutData adds (or replaces if the mapping key is the same) contextual data
@ -110,6 +114,11 @@ func (pe *PolicyEvaluator) PutData(ctx context.Context, data map[string]interfac
pe.mu.Lock() pe.mu.Lock()
defer pe.mu.Unlock() defer pe.mu.Unlock()
if ca, ok := data["client_ca"].(string); ok {
pe.clientCA = ca
}
txn, err := pe.store.NewTransaction(ctx, storage.WriteParams) txn, err := pe.store.NewTransaction(ctx, storage.WriteParams)
if err != nil { if err != nil {
return fmt.Errorf("opa: bad transaction: %w", err) return fmt.Errorf("opa: bad transaction: %w", err)
@ -171,12 +180,48 @@ func decisionFromInterface(i interface{}) (*pb.IsAuthorizedReply, error) {
if v, ok := m["signed_jwt"].(string); ok { if v, ok := m["signed_jwt"].(string); ok {
d.SignedJwt = v d.SignedJwt = v
} }
// http_status = [200, "OK", { "HEADER": "VALUE" }]
if v, ok := m["http_status"].([]interface{}); ok {
d.HttpStatus = new(pb.HTTPStatus)
if len(v) > 0 {
d.HttpStatus.Code = int32(anyToInt(v[0]))
}
if len(v) > 1 {
if msg, ok := v[1].(string); ok {
d.HttpStatus.Message = msg
}
}
if len(v) > 2 {
if headers, ok := v[2].(map[string]interface{}); ok {
d.HttpStatus.Headers = make(map[string]string)
for hk, hv := range headers {
d.HttpStatus.Headers[hk] = fmt.Sprint(hv)
}
}
}
}
return &d, nil return &d, nil
} }
func (pe *PolicyEvaluator) runBoolQuery(ctx context.Context, input interface{}, q rego.PreparedEvalQuery) (*pb.IsAuthorizedReply, error) { func (pe *PolicyEvaluator) runBoolQuery(ctx context.Context, req *evaluator.Request, q rego.PreparedEvalQuery) (*pb.IsAuthorizedReply, error) {
pe.mu.RLock() pe.mu.RLock()
defer pe.mu.RUnlock() defer pe.mu.RUnlock()
// `opa test` doesn't support custom function, so we'll pre-compute is_valid_client_certificate
isValid, err := isValidClientCertificate(pe.clientCA, req.ClientCertificate)
if err != nil {
return nil, fmt.Errorf("certificate error: %w", err)
}
input := struct {
*evaluator.Request
IsValidClientCertificate bool `json:"is_valid_client_certificate"`
}{
Request: req,
IsValidClientCertificate: isValid,
}
rs, err := q.Eval(ctx, rego.EvalInput(input)) rs, err := q.Eval(ctx, rego.EvalInput(input))
if err != nil { if err != nil {
return nil, fmt.Errorf("eval query: %w", err) return nil, fmt.Errorf("eval query: %w", err)
@ -199,3 +244,35 @@ func readPolicy(fn string) ([]byte, error) {
defer r.Close() defer r.Close()
return ioutil.ReadAll(r) return ioutil.ReadAll(r)
} }
func anyToInt(obj interface{}) int {
switch v := obj.(type) {
case int:
return v
case int64:
return int(v)
case int32:
return int(v)
case int16:
return int(v)
case int8:
return int(v)
case uint64:
return int(v)
case uint32:
return int(v)
case uint16:
return int(v)
case uint8:
return int(v)
case json.Number:
i, _ := v.Int64()
return int(i)
case string:
i, _ := strconv.Atoi(v)
return i
default:
i, _ := strconv.Atoi(fmt.Sprint(v))
return i
}
}

View file

@ -5,9 +5,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/pomerium/pomerium/config" "github.com/stretchr/testify/assert"
"gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt" "gopkg.in/square/go-jose.v2/jwt"
"github.com/pomerium/pomerium/authorize/evaluator"
"github.com/pomerium/pomerium/config"
) )
func Test_Eval(t *testing.T) { func Test_Eval(t *testing.T) {
@ -89,11 +92,7 @@ func Test_Eval(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
req := struct { req := &evaluator.Request{
Host string `json:"host,omitempty"`
URL string `json:"url,omitempty"`
User string `json:"user,omitempty"`
}{
Host: tt.route, Host: tt.route,
URL: "https://" + tt.route, URL: "https://" + tt.route,
User: rawJWT, User: rawJWT,
@ -108,3 +107,17 @@ func Test_Eval(t *testing.T) {
}) })
} }
} }
func Test_anyToInt(t *testing.T) {
assert.Equal(t, 5, anyToInt("5"))
assert.Equal(t, 7, anyToInt(7))
assert.Equal(t, 9, anyToInt(int8(9)))
assert.Equal(t, 9, anyToInt(int16(9)))
assert.Equal(t, 9, anyToInt(int32(9)))
assert.Equal(t, 9, anyToInt(int64(9)))
assert.Equal(t, 11, anyToInt(uint8(11)))
assert.Equal(t, 11, anyToInt(uint16(11)))
assert.Equal(t, 11, anyToInt(uint32(11)))
assert.Equal(t, 11, anyToInt(uint64(11)))
assert.Equal(t, 13, anyToInt(13.0))
}

View file

@ -5,6 +5,10 @@ import data.shared_key
default allow = false default allow = false
http_status = [495, "invalid client certificate"]{
not input.is_valid_client_certificate
}
# allow public # allow public
allow { allow {
route := first_allowed_route(input.url) route := first_allowed_route(input.url)

File diff suppressed because one or more lines are too long

View file

@ -20,7 +20,6 @@ import (
envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2" envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
envoy_type "github.com/envoyproxy/go-control-plane/envoy/type"
"google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
) )
@ -60,13 +59,14 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
requestURL := getCheckRequestURL(in) requestURL := getCheckRequestURL(in)
req := &evaluator.Request{ req := &evaluator.Request{
User: string(sess), User: string(sess),
Header: hdrs, Header: hdrs,
Host: hattrs.GetHost(), Host: hattrs.GetHost(),
Method: hattrs.GetMethod(), Method: hattrs.GetMethod(),
RequestURI: requestURL.String(), RequestURI: requestURL.String(),
RemoteAddr: in.GetAttributes().GetSource().GetAddress().String(), RemoteAddr: in.GetAttributes().GetSource().GetAddress().String(),
URL: requestURL.String(), URL: requestURL.String(),
ClientCertificate: getPeerCertificate(in),
} }
reply, err := a.pe.IsAuthorized(ctx, req) reply, err := a.pe.IsAuthorized(ctx, req)
if err != nil { if err != nil {
@ -88,7 +88,12 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
evt = evt.Strs("deny-reasons", reply.GetDenyReasons()) evt = evt.Strs("deny-reasons", reply.GetDenyReasons())
evt = evt.Str("email", reply.GetEmail()) evt = evt.Str("email", reply.GetEmail())
evt = evt.Strs("groups", reply.GetGroups()) evt = evt.Strs("groups", reply.GetGroups())
evt = evt.Str("session", string(sess)) if sess != nil {
evt = evt.Str("session", string(sess))
}
if reply.GetHttpStatus() != nil {
evt = evt.Interface("http_status", reply.GetHttpStatus())
}
evt.Msg("authorize check") evt.Msg("authorize check")
requestHeaders = append(requestHeaders, requestHeaders = append(requestHeaders,
@ -99,6 +104,14 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
}, },
}) })
if reply.GetHttpStatus().GetCode() > 0 && reply.GetHttpStatus().GetCode() != http.StatusOK {
return a.deniedResponse(in,
reply.GetHttpStatus().GetCode(),
reply.GetHttpStatus().GetMessage(),
reply.GetHttpStatus().GetHeaders(),
), nil
}
if reply.Allow { if reply.Allow {
return &envoy_service_auth_v2.CheckResponse{ return &envoy_service_auth_v2.CheckResponse{
Status: &status.Status{Code: int32(codes.OK), Message: "OK"}, Status: &status.Status{Code: int32(codes.OK), Message: "OK"},
@ -123,30 +136,12 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
msg = sesserr.Error() msg = sesserr.Error()
} }
// all other errors // all other errors
return &envoy_service_auth_v2.CheckResponse{ return a.deniedResponse(in, http.StatusForbidden, msg, nil), nil
Status: &status.Status{Code: int32(codes.PermissionDenied), Message: msg},
HttpResponse: &envoy_service_auth_v2.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v2.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode_Forbidden,
},
},
},
}, nil
} }
// no redirect for forward auth, that's handled by a separate config setting // no redirect for forward auth, that's handled by a separate config setting
if isForwardAuth { if isForwardAuth {
return &envoy_service_auth_v2.CheckResponse{ return a.deniedResponse(in, http.StatusUnauthorized, "Unauthenticated", nil), nil
Status: &status.Status{Code: int32(codes.Unauthenticated)},
HttpResponse: &envoy_service_auth_v2.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v2.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode_Unauthorized,
},
},
},
}, nil
} }
signinURL := opts.AuthenticateURL.ResolveReference(&url.URL{Path: "/.pomerium/sign_in"}) signinURL := opts.AuthenticateURL.ResolveReference(&url.URL{Path: "/.pomerium/sign_in"})
@ -155,25 +150,9 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
signinURL.RawQuery = q.Encode() signinURL.RawQuery = q.Encode()
redirectTo := urlutil.NewSignedURL(opts.SharedKey, signinURL).String() redirectTo := urlutil.NewSignedURL(opts.SharedKey, signinURL).String()
return &envoy_service_auth_v2.CheckResponse{ return a.deniedResponse(in, http.StatusFound, "Login", map[string]string{
Status: &status.Status{ "Location": redirectTo,
Code: int32(codes.Unauthenticated), }), nil
Message: "unauthenticated",
},
HttpResponse: &envoy_service_auth_v2.CheckResponse_DeniedResponse{
DeniedResponse: &envoy_service_auth_v2.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode_Found,
},
Headers: []*envoy_api_v2_core.HeaderValueOption{{
Header: &envoy_api_v2_core.HeaderValue{
Key: "Location",
Value: redirectTo,
},
}},
},
},
}, nil
} }
func (a *Authorize) getEnvoyRequestHeaders(rawjwt []byte, isNewSession bool) ([]*envoy_api_v2_core.HeaderValueOption, error) { func (a *Authorize) getEnvoyRequestHeaders(rawjwt []byte, isNewSession bool) ([]*envoy_api_v2_core.HeaderValueOption, error) {
@ -329,3 +308,10 @@ func handleForwardAuth(opts config.Options, req *envoy_service_auth_v2.CheckRequ
return false return false
} }
// getPeerCertificate gets the PEM-encoded peer certificate from the check request
func getPeerCertificate(in *envoy_service_auth_v2.CheckRequest) string {
// ignore the error as we will just return the empty string in that case
cert, _ := url.QueryUnescape(in.GetAttributes().GetSource().GetCertificate())
return cert
}

2
cache/grpc.go vendored
View file

@ -1,4 +1,4 @@
//go:generate protoc -I ../internal/grpc/cache/ --go_out=plugins=grpc:../internal/grpc/cache/ ../internal/grpc/cache/cache.proto //go:generate ../scripts/protoc -I ../internal/grpc/cache/ --go_out=plugins=grpc:../internal/grpc/cache/ ../internal/grpc/cache/cache.proto
package cache package cache

3
cache/grpc_test.go vendored
View file

@ -1,5 +1,3 @@
//go:generate protoc -I ../internal/grpc/cache/ --go_out=plugins=grpc:../internal/grpc/cache/ ../internal/grpc/cache/cache.proto
package cache package cache
import ( import (
@ -12,6 +10,7 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/cryptutil" "github.com/pomerium/pomerium/internal/cryptutil"
"github.com/pomerium/pomerium/internal/grpc/cache" "github.com/pomerium/pomerium/internal/grpc/cache"

View file

@ -238,6 +238,11 @@ type Options struct {
// CacheStorePath is the path to use for a given cache store. e.g. /etc/bolt.db // CacheStorePath is the path to use for a given cache store. e.g. /etc/bolt.db
CacheStorePath string `mapstructure:"cache_store_path" yaml:"cache_store_path,omitempty"` CacheStorePath string `mapstructure:"cache_store_path" yaml:"cache_store_path,omitempty"`
// ClientCA is the base64-encoded certificate authority to validate client mTLS certificates against.
ClientCA string `mapstructure:"client_ca" yaml:"client_ca,omitempty"`
// ClientCAFile points to a file that contains the certificate authority to validate client mTLS certificates against.
ClientCAFile string `mapstructure:"client_ca_file" yaml:"client_ca_file,omitempty"`
viper *viper.Viper viper *viper.Viper
} }
@ -562,6 +567,18 @@ func (o *Options) Validate() error {
o.Certificates = append(o.Certificates, *cert) o.Certificates = append(o.Certificates, *cert)
} }
if o.ClientCA != "" {
if _, err := base64.StdEncoding.DecodeString(o.ClientCA); err != nil {
return fmt.Errorf("config: bad client ca base64: %w", err)
}
}
if o.ClientCAFile != "" {
if _, err := os.Stat(o.ClientCAFile); err != nil {
return fmt.Errorf("config: bad client ca file: %w", err)
}
}
RedirectAndAutocertServer.update(o) RedirectAndAutocertServer.update(o)
err = AutocertManager.update(o) err = AutocertManager.update(o)

View file

@ -209,6 +209,15 @@ certificates:
key: "$HOME/.acme.sh/prometheus.example.com_ecc/prometheus.example.com.key" key: "$HOME/.acme.sh/prometheus.example.com_ecc/prometheus.example.com.key"
``` ```
### Client Certificate Authority
- Environment Variable: `CLIENT_CA` / `CLIENT_CA_FILE`
- Config File Key: `client_ca` / `client_ca_file`
- Type: [base64 encoded] `string` or relative file location
- Optional
The Client Certificate Authority is the x509 _public-key_ used to validate [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication) client certificates. If not set, no client certificate will be required.
### Global Timeouts ### Global Timeouts
- Environmental Variables: `TIMEOUT_READ` `TIMEOUT_WRITE` `TIMEOUT_IDLE` - Environmental Variables: `TIMEOUT_READ` `TIMEOUT_WRITE` `TIMEOUT_IDLE`

1
go.mod
View file

@ -20,6 +20,7 @@ require (
github.com/gorilla/handlers v1.4.2 github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.4 github.com/gorilla/mux v1.7.4
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.4
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lithammer/shortuuid/v3 v3.0.4 github.com/lithammer/shortuuid/v3 v3.0.4
github.com/mitchellh/hashstructure v1.0.0 github.com/mitchellh/hashstructure v1.0.0

View file

@ -9,6 +9,6 @@ import (
const Luascripts = "luascripts" // static asset namespace const Luascripts = "luascripts" // static asset namespace
func init() { func init() {
data := "PK\x03\x04\x14\x00\x08\x00\x08\x00el\xb3P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x00clean-upstream.luaUT\x05\x00\x01\x8f\xe0\xc3^\x94S\xc1n\x9c0\x10\xbd\xf3\x15O\xf4PV%\x91z\xdd\xc8\xff\xd0{\xd5\"\x17f\x17\xab`\xbb\xf68\x9b\xe4\xd0o\xaf\xbc\x18\x16\x07VU|\xc0cy\xde\x9b\xc7\x9b\xf1)\xe8\x96\x95\xd1p4\x9agj\xac\x19\xc9\xa906\xad1\xbf\x15U\xd3\xd6h9R\x8d\xe9p(\x00\xe0\xe1\x01C\x90\xe8\x0cy\xfd\x99\xe1\x83\xb5\xc61\x8c\x8dlr@+-\x07G8;\x13\xac\x9f!\xde\xe0Bpd\x07\xd9\x12\xf8\xa2\xe2\xd7\xa0\x97\xba\x1b\x08sq\xf1\xf2\xfa\x06\xc9\xe0\x9e@\xba\x839]C\xcfN\xe9\xf3\x95jR\x02\x91\x82\xe3\xd9\x87_k\xadx|D)\xbe\xff|\xfa\xf1\xe5 e\x8d\xb2<|\x14\xb7B9\xe2\xe0t\xc2\x14\xa4\xbb\xa2X|\xeb\xa5o\xac\xa3\x93z\xa9<\xbb\x1aS\x9c\xe1<;\xfc\x15\xd0j\x80\xd4]<\x1ec\xd9\xaf5>\xa5l\x08\x91\x80\xef\xd8I?\x9b\xd7\xc6\xe8\xc6\xd1\x9f@\x9e\xab\xb47\x93cS\x99\xc1\xb4r@O\xb2#\xe7!\x90\xe7\x1c\xd3E\xb5N\x1e\x89e'Yn\xb3\xe7\x9b\xeaP\xac\xf2\xd3t\xac\x9d\x12\x0b\xc9\xf1L\\\x95\xfb\x03\x94\x1cT\xa7=\n\xeeI_\xafo\x85\x96\x06%\xd5\x13w\xc6\x95\xf8Rf26\xa3\x8aK\xd3e\xe1\xba3\xdb[E\xf9\x88\xcfk\x96\x92\xc6v\x91S\xdf\x8a\xdc\x00\xb1\x7f\xf3\xbe5P\x06\xee\x8dSo\xf2\xda\xdd\xffY\x98eo\x9c\xcc\xb9v\xbc|_,\xb3t\x8f\xfb\x0e4\xcd7\x04\xcaoI\x1a\xcau+Vo \x03\xd6\xbb<\x87m\xb3n\x0e\xc7?\xbb/nm\xee\xdd\x87\xe2\xad\xd1>vw\n\x96\xa7\x12\x11\xff\x02\x00\x00\xff\xffPK\x07\x08\x08Z\x88f\xa3\x01\x00\x00\xef\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x10\x9d\xb2P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x00ext-authz-set-cookie.luaUT\x05\x00\x01\xb0\xe4\xc2^\x8c\x91An\x830\x10E\xf7\x9cb\xc4\xcaHI\x0e\x80\x94\x03t\xd1\x13T\x955\xc5C\xb0j\x8fS{\x88\x9aM\xcf^AM\x04\x0dM\x19 \x01\xe2\xff?\xf8\xbf\xb6\xe7Fl` \xbe\x84\xab\x0e\xac#}\xf4\x94D\xe5\xbb\xee\x90\x8d\xa3\xaa\x00\x00p\xa1A\x07\x1d\xa1\xa1\x98\xe0\x08KM\x9d?\xa8\xb9\xd8\\\x19\xbdm\xb4'\xc1{G\x92H\xe8\x9f\xb8\x0d\xaa\xaa\xb3\xf4\x99\x04\x0d\n\xe6\x18\xdbN\x0b\xeb\x13\x89*?\xf7\xe7\xe0)\xda\xde\xef\x13\xc9\xbe \xe1\xddRY\xc1\xd7\x11\xd8:\x90\x8ex\xf4\x0d3_^\xa7\xc1=\x1e\xf3\xd0Z'\x14\xd3\xa1\x139\x1f\\\x8f\xe5\x0e\xca)U'\x12\x9dSw\xb7\xa4\xbb\xd9\xf2OU\xf1[\x1d\xc9\x87\x0b\xfdi\x18\xf5\xc4\xa6\x18\xaeb\x8dM:\x07N\xa4\xa6\x87\x7f\xe8,D\xdb\xf0,-\x1b\xf8\xfc\xe4\xc8\x9b\x83\xe3\xb2\xef\xd3\x83\xbeoh\x07_&\x87l\x86\xd7\x97U\x12\xaf\xab|\xa7Z\xd1\x18U\xce\x8a\xdc=\x08Z\x96\xfc\x1d\x00\x00\xff\xffPK\x07\x08\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00el\xb3P\x08Z\x88f\xa3\x01\x00\x00\xef\x04\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00clean-upstream.luaUT\x05\x00\x01\x8f\xe0\xc3^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x10\x9d\xb2P\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\xec\x01\x00\x00ext-authz-set-cookie.luaUT\x05\x00\x01\xb0\xe4\xc2^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x00B\x03\x00\x00\x00\x00" data := "PK\x03\x04\x14\x00\x08\x00\x08\x00@\x89\xb3P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x00clean-upstream.luaUT\x05\x00\x01\xe8\x12\xc4^\x94S\xc1n\x9c0\x10\xbd\xf3\x15O\xf4PV%\x91z\xdd\xc8\xff\xd0{\xd5\"\x17f\x17\xab`\xbb\xf68\x9b\xe4\xd0o\xaf\x00\xc3\xe2\x00\xaa\xe2\x03\x1e\xcb\xf3\xde<\xde\x8c/A\xd7\xac\x8c\x86\xa3\xde<SeMON\x85\xbe\xaa\x8d\xf9\xad\xa8\x98\xb6J\xcb\x9eJL\x87S\x06\x00\x0f\x0f\xe8\x82Dc\xc8\xeb\xcf\x0c\x1f\xac5\x8ea\xec\xc0&;\xd4\xd2rp\x84\xab3\xc1\xfa\x19\xe2\x0dn\x04G\xb6\x935\x81oj\xf8\x1a\xb4R7\x1da..^^\xdf \x19\xdc\x12H70\x971\xf4\xec\x94\xbe\x8eT\x93\x12\x88\x18\x9c\xaf>\xfcZk\xc5\xe3#r\xf1\xfd\xe7\xd3\x8f/O\xc8K\xe4\xf9\xe9\xa3\xb8\x15\xca\x11\x07\xa7#&#\xddd\xd9\xe2[+}e\x1d]\xd4K\xe1\xd9\x95\x98\xe2\x04\xe7\xd9\xe1\xaf\x80V\x1d\xa4n\x86\xe3y(\xfb\xb5\xc4\xa7\x98\x0d!\"\xf0\x1d;\xe9g\xf3Z\x19]9\xfa\x13\xc8s\x11\xf7jrl*\xd3\x99ZvhI6\xe4<\x04\xd2\x9cs\xbc(\xd6\xc9=\xb1l$\xcbm\xf6|S\x9c\xb2U~\x9c\x8e\xb5Sb!9_\x89\x8b|\x7f\x80\xa2\x83\xea\xb2G\xc1-\xe9\xf1\xfa^hiPT=q'\\\x91/fFc\x13\xaaai\xba-\\\x07\xb3\xbdU\x94\x8e\xf8\xbcf)ql\x179\xe5\xbd\xc8\x1d0\xf4o\xde\xb7\x06\xca\xc0\xadq\xeaM\x8e\xdd\xfd\x9f\x85I\xf6\xc6\xc9\x94k\xc7\xcb\xf7\xc5\x12K\xf7\xb8\x0f\xa0q\xbe!\x90\x7f\x8b\xd2\x90\xaf[\xb1z\x03 \xb0\xdc\xe59m\x9buwx\xf8\xb3cqks\x0f\x1f\x8a\xb7F\xfb\xa1\xbbS\xb0<\x95\x11\xf1/\x00\x00\xff\xffPK\x07\x08\xfb\x06j<\xa2\x01\x00\x00\xf0\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00bz\xb3P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x00ext-authz-set-cookie.luaUT\x05\x00\x01\xe8\xf8\xc3^\x8c\x91An\x830\x10E\xf7\x9cb\xc4\xcaHI\x0e\x80\x94\x03t\xd1\x13T\x955\xc5C\xb0j\x8fS{\x88\x9aM\xcf^AM\x04\x0dM\x19 \x01\xe2\xff?\xf8\xbf\xb6\xe7Fl` \xbe\x84\xab\x0e\xac#}\xf4\x94D\xe5\xbb\xee\x90\x8d\xa3\xaa\x00\x00p\xa1A\x07\x1d\xa1\xa1\x98\xe0\x08KM\x9d?\xa8\xb9\xd8\\\x19\xbdm\xb4'\xc1{G\x92H\xe8\x9f\xb8\x0d\xaa\xaa\xb3\xf4\x99\x04\x0d\n\xe6\x18\xdbN\x0b\xeb\x13\x89*?\xf7\xe7\xe0)\xda\xde\xef\x13\xc9\xbe \xe1\xddRY\xc1\xd7\x11\xd8:\x90\x8ex\xf4\x0d3_^\xa7\xc1=\x1e\xf3\xd0Z'\x14\xd3\xa1\x139\x1f\\\x8f\xe5\x0e\xca)U'\x12\x9dSw\xb7\xa4\xbb\xd9\xf2OU\xf1[\x1d\xc9\x87\x0b\xfdi\x18\xf5\xc4\xa6\x18\xaeb\x8dM:\x07N\xa4\xa6\x87\x7f\xe8,D\xdb\xf0,-\x1b\xf8\xfc\xe4\xc8\x9b\x83\xe3\xb2\xef\xd3\x83\xbeoh\x07_&\x87l\x86\xd7\x97U\x12\xaf\xab|\xa7Z\xd1\x18U\xce\x8a\xdc=\x08Z\x96\xfc\x1d\x00\x00\xff\xffPK\x07\x08\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00@\x89\xb3P\xfb\x06j<\xa2\x01\x00\x00\xf0\x04\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00clean-upstream.luaUT\x05\x00\x01\xe8\x12\xc4^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00bz\xb3P\x93\xe7\xad\x94\x07\x01\x00\x00\x00\x03\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\xeb\x01\x00\x00ext-authz-set-cookie.luaUT\x05\x00\x01\xe8\xf8\xc3^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x00A\x03\x00\x00\x00\x00"
fs.RegisterWithNamespace("luascripts", data) fs.RegisterWithNamespace("luascripts", data)
} }

View file

@ -1,6 +1,7 @@
package controlplane package controlplane
import ( import (
"encoding/base64"
"sort" "sort"
"time" "time"
@ -164,6 +165,7 @@ func (srv *Server) buildMainHTTPConnectionManagerFilter(options *config.Options,
}, },
}, },
}, },
IncludePeerCertificate: true,
}) })
extAuthzSetCookieLua, _ := ptypes.MarshalAny(&envoy_extensions_filters_http_lua_v3.Lua{ extAuthzSetCookieLua, _ := ptypes.MarshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
@ -326,11 +328,28 @@ func (srv *Server) buildDownstreamTLSContext(options *config.Options, domain str
return nil return nil
} }
var trustedCA *envoy_config_core_v3.DataSource
if options.ClientCA != "" {
bs, err := base64.StdEncoding.DecodeString(options.ClientCA)
if err != nil {
log.Warn().Msg("client_ca does not appear to be a base64 encoded string")
}
trustedCA = inlineBytesAsFilename("client-ca", bs)
} else if options.ClientCAFile != "" {
trustedCA = inlineFilename(options.ClientCAFile)
}
envoyCert := envoyTLSCertificateFromGoTLSCertificate(cert) envoyCert := envoyTLSCertificateFromGoTLSCertificate(cert)
return &envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{ return &envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{
CommonTlsContext: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext{ CommonTlsContext: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext{
TlsCertificates: []*envoy_extensions_transport_sockets_tls_v3.TlsCertificate{envoyCert}, TlsCertificates: []*envoy_extensions_transport_sockets_tls_v3.TlsCertificate{envoyCert},
AlpnProtocols: []string{"h2", "http/1.1"}, AlpnProtocols: []string{"h2", "http/1.1"},
ValidationContextType: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext{
ValidationContext: &envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext{
TrustedCa: trustedCA,
TrustChainVerification: envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext_ACCEPT_UNTRUSTED,
},
},
}, },
} }
} }

File diff suppressed because one or more lines are too long

View file

@ -1,30 +1,39 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.23.0
// protoc v3.12.1
// source: authorize.proto // source: authorize.proto
package authorize package authorize
import ( import (
context "context" context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes" codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status" status "google.golang.org/grpc/status"
math "math" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
) )
// Reference imports to suppress errors if they are not otherwise used. const (
var _ = proto.Marshal // Verify that this generated code is sufficiently up-to-date.
var _ = fmt.Errorf _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
var _ = math.Inf // Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion that a sufficiently up-to-date version
// is compatible with the proto package it is being compiled against. // of the legacy proto package is being used.
// A compilation error at this line likely means your copy of the const _ = proto.ProtoPackageIsVersion4
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type IsAuthorizedRequest struct { type IsAuthorizedRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// User Context // User Context
// //
UserToken string `protobuf:"bytes,1,opt,name=user_token,json=userToken,proto3" json:"user_token,omitempty"` UserToken string `protobuf:"bytes,1,opt,name=user_token,json=userToken,proto3" json:"user_token,omitempty"`
@ -41,254 +50,486 @@ type IsAuthorizedRequest struct {
RequestRequestUri string `protobuf:"bytes,5,opt,name=request_request_uri,json=requestRequestUri,proto3" json:"request_request_uri,omitempty"` RequestRequestUri string `protobuf:"bytes,5,opt,name=request_request_uri,json=requestRequestUri,proto3" json:"request_request_uri,omitempty"`
// RemoteAddr allows HTTP servers and other software to record // RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for // the network address that sent the request, usually for
RequestRemoteAddr string `protobuf:"bytes,6,opt,name=request_remote_addr,json=requestRemoteAddr,proto3" json:"request_remote_addr,omitempty"` RequestRemoteAddr string `protobuf:"bytes,6,opt,name=request_remote_addr,json=requestRemoteAddr,proto3" json:"request_remote_addr,omitempty"`
RequestHeaders map[string]*IsAuthorizedRequest_Headers `protobuf:"bytes,7,rep,name=request_headers,json=requestHeaders,proto3" json:"request_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` RequestHeaders map[string]*IsAuthorizedRequest_Headers `protobuf:"bytes,7,rep,name=request_headers,json=requestHeaders,proto3" json:"request_headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *IsAuthorizedRequest) Reset() { *m = IsAuthorizedRequest{} } func (x *IsAuthorizedRequest) Reset() {
func (m *IsAuthorizedRequest) String() string { return proto.CompactTextString(m) } *x = IsAuthorizedRequest{}
func (*IsAuthorizedRequest) ProtoMessage() {} if protoimpl.UnsafeEnabled {
mi := &file_authorize_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IsAuthorizedRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IsAuthorizedRequest) ProtoMessage() {}
func (x *IsAuthorizedRequest) ProtoReflect() protoreflect.Message {
mi := &file_authorize_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IsAuthorizedRequest.ProtoReflect.Descriptor instead.
func (*IsAuthorizedRequest) Descriptor() ([]byte, []int) { func (*IsAuthorizedRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_ffbc3c71370bee9a, []int{0} return file_authorize_proto_rawDescGZIP(), []int{0}
} }
func (m *IsAuthorizedRequest) XXX_Unmarshal(b []byte) error { func (x *IsAuthorizedRequest) GetUserToken() string {
return xxx_messageInfo_IsAuthorizedRequest.Unmarshal(m, b) if x != nil {
} return x.UserToken
func (m *IsAuthorizedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IsAuthorizedRequest.Marshal(b, m, deterministic)
}
func (m *IsAuthorizedRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_IsAuthorizedRequest.Merge(m, src)
}
func (m *IsAuthorizedRequest) XXX_Size() int {
return xxx_messageInfo_IsAuthorizedRequest.Size(m)
}
func (m *IsAuthorizedRequest) XXX_DiscardUnknown() {
xxx_messageInfo_IsAuthorizedRequest.DiscardUnknown(m)
}
var xxx_messageInfo_IsAuthorizedRequest proto.InternalMessageInfo
func (m *IsAuthorizedRequest) GetUserToken() string {
if m != nil {
return m.UserToken
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestMethod() string { func (x *IsAuthorizedRequest) GetRequestMethod() string {
if m != nil { if x != nil {
return m.RequestMethod return x.RequestMethod
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestUrl() string { func (x *IsAuthorizedRequest) GetRequestUrl() string {
if m != nil { if x != nil {
return m.RequestUrl return x.RequestUrl
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestHost() string { func (x *IsAuthorizedRequest) GetRequestHost() string {
if m != nil { if x != nil {
return m.RequestHost return x.RequestHost
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestRequestUri() string { func (x *IsAuthorizedRequest) GetRequestRequestUri() string {
if m != nil { if x != nil {
return m.RequestRequestUri return x.RequestRequestUri
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestRemoteAddr() string { func (x *IsAuthorizedRequest) GetRequestRemoteAddr() string {
if m != nil { if x != nil {
return m.RequestRemoteAddr return x.RequestRemoteAddr
} }
return "" return ""
} }
func (m *IsAuthorizedRequest) GetRequestHeaders() map[string]*IsAuthorizedRequest_Headers { func (x *IsAuthorizedRequest) GetRequestHeaders() map[string]*IsAuthorizedRequest_Headers {
if m != nil { if x != nil {
return m.RequestHeaders return x.RequestHeaders
}
return nil
}
type IsAuthorizedReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Allow bool `protobuf:"varint,1,opt,name=allow,proto3" json:"allow,omitempty"`
SessionExpired bool `protobuf:"varint,2,opt,name=session_expired,json=sessionExpired,proto3" json:"session_expired,omitempty"` // special case
DenyReasons []string `protobuf:"bytes,3,rep,name=deny_reasons,json=denyReasons,proto3" json:"deny_reasons,omitempty"`
SignedJwt string `protobuf:"bytes,4,opt,name=signed_jwt,json=signedJwt,proto3" json:"signed_jwt,omitempty"`
User string `protobuf:"bytes,5,opt,name=user,proto3" json:"user,omitempty"`
Email string `protobuf:"bytes,6,opt,name=email,proto3" json:"email,omitempty"`
Groups []string `protobuf:"bytes,7,rep,name=groups,proto3" json:"groups,omitempty"`
HttpStatus *HTTPStatus `protobuf:"bytes,8,opt,name=http_status,json=httpStatus,proto3" json:"http_status,omitempty"`
}
func (x *IsAuthorizedReply) Reset() {
*x = IsAuthorizedReply{}
if protoimpl.UnsafeEnabled {
mi := &file_authorize_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IsAuthorizedReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IsAuthorizedReply) ProtoMessage() {}
func (x *IsAuthorizedReply) ProtoReflect() protoreflect.Message {
mi := &file_authorize_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IsAuthorizedReply.ProtoReflect.Descriptor instead.
func (*IsAuthorizedReply) Descriptor() ([]byte, []int) {
return file_authorize_proto_rawDescGZIP(), []int{1}
}
func (x *IsAuthorizedReply) GetAllow() bool {
if x != nil {
return x.Allow
}
return false
}
func (x *IsAuthorizedReply) GetSessionExpired() bool {
if x != nil {
return x.SessionExpired
}
return false
}
func (x *IsAuthorizedReply) GetDenyReasons() []string {
if x != nil {
return x.DenyReasons
}
return nil
}
func (x *IsAuthorizedReply) GetSignedJwt() string {
if x != nil {
return x.SignedJwt
}
return ""
}
func (x *IsAuthorizedReply) GetUser() string {
if x != nil {
return x.User
}
return ""
}
func (x *IsAuthorizedReply) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *IsAuthorizedReply) GetGroups() []string {
if x != nil {
return x.Groups
}
return nil
}
func (x *IsAuthorizedReply) GetHttpStatus() *HTTPStatus {
if x != nil {
return x.HttpStatus
}
return nil
}
type HTTPStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *HTTPStatus) Reset() {
*x = HTTPStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_authorize_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HTTPStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HTTPStatus) ProtoMessage() {}
func (x *HTTPStatus) ProtoReflect() protoreflect.Message {
mi := &file_authorize_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HTTPStatus.ProtoReflect.Descriptor instead.
func (*HTTPStatus) Descriptor() ([]byte, []int) {
return file_authorize_proto_rawDescGZIP(), []int{2}
}
func (x *HTTPStatus) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *HTTPStatus) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *HTTPStatus) GetHeaders() map[string]string {
if x != nil {
return x.Headers
} }
return nil return nil
} }
// headers represents key-value pairs in an HTTP header; map[string][]string // headers represents key-value pairs in an HTTP header; map[string][]string
type IsAuthorizedRequest_Headers struct { type IsAuthorizedRequest_Headers struct {
Value []string `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` state protoimpl.MessageState
XXX_NoUnkeyedLiteral struct{} `json:"-"` sizeCache protoimpl.SizeCache
XXX_unrecognized []byte `json:"-"` unknownFields protoimpl.UnknownFields
XXX_sizecache int32 `json:"-"`
Value []string `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"`
} }
func (m *IsAuthorizedRequest_Headers) Reset() { *m = IsAuthorizedRequest_Headers{} } func (x *IsAuthorizedRequest_Headers) Reset() {
func (m *IsAuthorizedRequest_Headers) String() string { return proto.CompactTextString(m) } *x = IsAuthorizedRequest_Headers{}
func (*IsAuthorizedRequest_Headers) ProtoMessage() {} if protoimpl.UnsafeEnabled {
mi := &file_authorize_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IsAuthorizedRequest_Headers) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IsAuthorizedRequest_Headers) ProtoMessage() {}
func (x *IsAuthorizedRequest_Headers) ProtoReflect() protoreflect.Message {
mi := &file_authorize_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IsAuthorizedRequest_Headers.ProtoReflect.Descriptor instead.
func (*IsAuthorizedRequest_Headers) Descriptor() ([]byte, []int) { func (*IsAuthorizedRequest_Headers) Descriptor() ([]byte, []int) {
return fileDescriptor_ffbc3c71370bee9a, []int{0, 0} return file_authorize_proto_rawDescGZIP(), []int{0, 0}
} }
func (m *IsAuthorizedRequest_Headers) XXX_Unmarshal(b []byte) error { func (x *IsAuthorizedRequest_Headers) GetValue() []string {
return xxx_messageInfo_IsAuthorizedRequest_Headers.Unmarshal(m, b) if x != nil {
} return x.Value
func (m *IsAuthorizedRequest_Headers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IsAuthorizedRequest_Headers.Marshal(b, m, deterministic)
}
func (m *IsAuthorizedRequest_Headers) XXX_Merge(src proto.Message) {
xxx_messageInfo_IsAuthorizedRequest_Headers.Merge(m, src)
}
func (m *IsAuthorizedRequest_Headers) XXX_Size() int {
return xxx_messageInfo_IsAuthorizedRequest_Headers.Size(m)
}
func (m *IsAuthorizedRequest_Headers) XXX_DiscardUnknown() {
xxx_messageInfo_IsAuthorizedRequest_Headers.DiscardUnknown(m)
}
var xxx_messageInfo_IsAuthorizedRequest_Headers proto.InternalMessageInfo
func (m *IsAuthorizedRequest_Headers) GetValue() []string {
if m != nil {
return m.Value
} }
return nil return nil
} }
type IsAuthorizedReply struct { var File_authorize_proto protoreflect.FileDescriptor
Allow bool `protobuf:"varint,1,opt,name=allow,proto3" json:"allow,omitempty"`
SessionExpired bool `protobuf:"varint,2,opt,name=session_expired,json=sessionExpired,proto3" json:"session_expired,omitempty"` var file_authorize_proto_rawDesc = []byte{
DenyReasons []string `protobuf:"bytes,3,rep,name=deny_reasons,json=denyReasons,proto3" json:"deny_reasons,omitempty"` 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
SignedJwt string `protobuf:"bytes,4,opt,name=signed_jwt,json=signedJwt,proto3" json:"signed_jwt,omitempty"` 0x6f, 0x12, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x22, 0xe8, 0x03, 0x0a,
User string `protobuf:"bytes,5,opt,name=user,proto3" json:"user,omitempty"` 0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71,
Email string `protobuf:"bytes,6,opt,name=email,proto3" json:"email,omitempty"` 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b,
Groups []string `protobuf:"bytes,7,rep,name=groups,proto3" json:"groups,omitempty"` 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x54, 0x6f,
XXX_NoUnkeyedLiteral struct{} `json:"-"` 0x6b, 0x65, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6d,
XXX_unrecognized []byte `json:"-"` 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71,
XXX_sizecache int32 `json:"-"` 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x55, 0x72, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x72,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2e,
0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x55, 0x72, 0x69, 0x12, 0x2e,
0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x5b,
0x0a, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x7a, 0x65, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x1f, 0x0a, 0x07, 0x48,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x69, 0x0a, 0x13,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 0x3c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8e, 0x02, 0x0a, 0x11, 0x49, 0x73, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a,
0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c,
0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65,
0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c,
0x64, 0x65, 0x6e, 0x79, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6e, 0x79, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x12,
0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6a, 0x77, 0x74, 0x18, 0x04, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4a, 0x77, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73,
0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73,
0x12, 0x36, 0x0a, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x65, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a, 0x68, 0x74,
0x74, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x0a, 0x48, 0x54, 0x54,
0x50, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x7a, 0x65, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x48, 0x65,
0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64,
0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 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, 0x32,
0x5c, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x4e, 0x0a,
0x0c, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1e, 0x2e,
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
func (m *IsAuthorizedReply) Reset() { *m = IsAuthorizedReply{} } var (
func (m *IsAuthorizedReply) String() string { return proto.CompactTextString(m) } file_authorize_proto_rawDescOnce sync.Once
func (*IsAuthorizedReply) ProtoMessage() {} file_authorize_proto_rawDescData = file_authorize_proto_rawDesc
func (*IsAuthorizedReply) Descriptor() ([]byte, []int) { )
return fileDescriptor_ffbc3c71370bee9a, []int{1}
func file_authorize_proto_rawDescGZIP() []byte {
file_authorize_proto_rawDescOnce.Do(func() {
file_authorize_proto_rawDescData = protoimpl.X.CompressGZIP(file_authorize_proto_rawDescData)
})
return file_authorize_proto_rawDescData
} }
func (m *IsAuthorizedReply) XXX_Unmarshal(b []byte) error { var file_authorize_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
return xxx_messageInfo_IsAuthorizedReply.Unmarshal(m, b) var file_authorize_proto_goTypes = []interface{}{
(*IsAuthorizedRequest)(nil), // 0: authorize.IsAuthorizedRequest
(*IsAuthorizedReply)(nil), // 1: authorize.IsAuthorizedReply
(*HTTPStatus)(nil), // 2: authorize.HTTPStatus
(*IsAuthorizedRequest_Headers)(nil), // 3: authorize.IsAuthorizedRequest.Headers
nil, // 4: authorize.IsAuthorizedRequest.RequestHeadersEntry
nil, // 5: authorize.HTTPStatus.HeadersEntry
} }
func (m *IsAuthorizedReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { var file_authorize_proto_depIdxs = []int32{
return xxx_messageInfo_IsAuthorizedReply.Marshal(b, m, deterministic) 4, // 0: authorize.IsAuthorizedRequest.request_headers:type_name -> authorize.IsAuthorizedRequest.RequestHeadersEntry
} 2, // 1: authorize.IsAuthorizedReply.http_status:type_name -> authorize.HTTPStatus
func (m *IsAuthorizedReply) XXX_Merge(src proto.Message) { 5, // 2: authorize.HTTPStatus.headers:type_name -> authorize.HTTPStatus.HeadersEntry
xxx_messageInfo_IsAuthorizedReply.Merge(m, src) 3, // 3: authorize.IsAuthorizedRequest.RequestHeadersEntry.value:type_name -> authorize.IsAuthorizedRequest.Headers
} 0, // 4: authorize.Authorizer.IsAuthorized:input_type -> authorize.IsAuthorizedRequest
func (m *IsAuthorizedReply) XXX_Size() int { 1, // 5: authorize.Authorizer.IsAuthorized:output_type -> authorize.IsAuthorizedReply
return xxx_messageInfo_IsAuthorizedReply.Size(m) 5, // [5:6] is the sub-list for method output_type
} 4, // [4:5] is the sub-list for method input_type
func (m *IsAuthorizedReply) XXX_DiscardUnknown() { 4, // [4:4] is the sub-list for extension type_name
xxx_messageInfo_IsAuthorizedReply.DiscardUnknown(m) 4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
} }
var xxx_messageInfo_IsAuthorizedReply proto.InternalMessageInfo func init() { file_authorize_proto_init() }
func file_authorize_proto_init() {
func (m *IsAuthorizedReply) GetAllow() bool { if File_authorize_proto != nil {
if m != nil { return
return m.Allow
} }
return false if !protoimpl.UnsafeEnabled {
} file_authorize_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IsAuthorizedRequest); i {
func (m *IsAuthorizedReply) GetSessionExpired() bool { case 0:
if m != nil { return &v.state
return m.SessionExpired case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_authorize_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IsAuthorizedReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_authorize_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HTTPStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_authorize_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IsAuthorizedRequest_Headers); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
return false type x struct{}
} out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
func (m *IsAuthorizedReply) GetDenyReasons() []string { GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
if m != nil { RawDescriptor: file_authorize_proto_rawDesc,
return m.DenyReasons NumEnums: 0,
} NumMessages: 6,
return nil NumExtensions: 0,
} NumServices: 1,
},
func (m *IsAuthorizedReply) GetSignedJwt() string { GoTypes: file_authorize_proto_goTypes,
if m != nil { DependencyIndexes: file_authorize_proto_depIdxs,
return m.SignedJwt MessageInfos: file_authorize_proto_msgTypes,
} }.Build()
return "" File_authorize_proto = out.File
} file_authorize_proto_rawDesc = nil
file_authorize_proto_goTypes = nil
func (m *IsAuthorizedReply) GetUser() string { file_authorize_proto_depIdxs = nil
if m != nil {
return m.User
}
return ""
}
func (m *IsAuthorizedReply) GetEmail() string {
if m != nil {
return m.Email
}
return ""
}
func (m *IsAuthorizedReply) GetGroups() []string {
if m != nil {
return m.Groups
}
return nil
}
func init() {
proto.RegisterType((*IsAuthorizedRequest)(nil), "authorize.IsAuthorizedRequest")
proto.RegisterMapType((map[string]*IsAuthorizedRequest_Headers)(nil), "authorize.IsAuthorizedRequest.RequestHeadersEntry")
proto.RegisterType((*IsAuthorizedRequest_Headers)(nil), "authorize.IsAuthorizedRequest.Headers")
proto.RegisterType((*IsAuthorizedReply)(nil), "authorize.IsAuthorizedReply")
}
func init() {
proto.RegisterFile("authorize.proto", fileDescriptor_ffbc3c71370bee9a)
}
var fileDescriptor_ffbc3c71370bee9a = []byte{
// 431 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xcf, 0x6e, 0x13, 0x31,
0x10, 0xc6, 0xd9, 0x6e, 0x9b, 0x76, 0x27, 0xa5, 0xa1, 0x13, 0x84, 0xac, 0x08, 0x68, 0x88, 0x04,
0xe4, 0x94, 0x43, 0xb8, 0x20, 0xc4, 0xa5, 0x87, 0x4a, 0x05, 0x09, 0x0e, 0x16, 0x9c, 0x40, 0x5a,
0x2d, 0xf2, 0xa8, 0x59, 0xea, 0xac, 0x17, 0xdb, 0x4b, 0x58, 0x1e, 0x94, 0x67, 0xe0, 0x31, 0x90,
0xff, 0xa5, 0x14, 0x15, 0x38, 0xad, 0xe7, 0xe7, 0xcf, 0xe3, 0x99, 0xf9, 0xbc, 0x30, 0xaa, 0x3a,
0xbb, 0x52, 0xba, 0xfe, 0x4e, 0x8b, 0x56, 0x2b, 0xab, 0xb0, 0xd8, 0x82, 0xd9, 0xcf, 0x1c, 0xc6,
0xaf, 0xcc, 0x69, 0x8a, 0x05, 0xa7, 0x2f, 0x1d, 0x19, 0x8b, 0x0f, 0x00, 0x3a, 0x43, 0xba, 0xb4,
0xea, 0x92, 0x1a, 0x96, 0x4d, 0xb3, 0x79, 0xc1, 0x0b, 0x47, 0xde, 0x39, 0x80, 0x8f, 0xe1, 0x48,
0x07, 0x65, 0xb9, 0x26, 0xbb, 0x52, 0x82, 0xed, 0x78, 0xc9, 0xed, 0x48, 0xdf, 0x78, 0x88, 0x27,
0x30, 0x4c, 0xb2, 0x4e, 0x4b, 0x96, 0x7b, 0x0d, 0x44, 0xf4, 0x5e, 0x4b, 0x7c, 0x04, 0x87, 0x49,
0xb0, 0x52, 0xc6, 0xb2, 0x5d, 0xaf, 0x48, 0x87, 0xce, 0x95, 0xb1, 0xb8, 0x80, 0x71, 0x92, 0x5c,
0xe5, 0xaa, 0xd9, 0x9e, 0x57, 0x1e, 0x47, 0xc4, 0x53, 0xca, 0xfa, 0xba, 0x7e, 0xad, 0x2c, 0x95,
0x95, 0x10, 0x9a, 0x0d, 0xfe, 0xd0, 0xbb, 0x9d, 0x53, 0x21, 0x34, 0x7e, 0x80, 0xd1, 0xb6, 0x04,
0xaa, 0x04, 0x69, 0xc3, 0xf6, 0xa7, 0xf9, 0x7c, 0xb8, 0x5c, 0x2e, 0xae, 0xe6, 0x76, 0xc3, 0x88,
0x16, 0xf1, 0x7b, 0x1e, 0x0e, 0x9d, 0x35, 0x56, 0xf7, 0x3c, 0x4d, 0x25, 0xc2, 0xc9, 0x09, 0xec,
0xc7, 0x25, 0xde, 0x85, 0xbd, 0xaf, 0x95, 0xec, 0x88, 0x65, 0xd3, 0x7c, 0x5e, 0xf0, 0x10, 0x4c,
0x6a, 0x18, 0xdf, 0x90, 0x07, 0xef, 0x40, 0x7e, 0x49, 0x7d, 0x9c, 0xbb, 0x5b, 0xe2, 0xcb, 0x74,
0xdc, 0x0d, 0x7a, 0xb8, 0x7c, 0xf2, 0x9f, 0xe2, 0x62, 0xb6, 0x78, 0xcd, 0x8b, 0x9d, 0xe7, 0xd9,
0xec, 0x47, 0x06, 0xc7, 0xd7, 0xa5, 0xad, 0xec, 0x5d, 0x59, 0x95, 0x94, 0x6a, 0xe3, 0xef, 0x3a,
0xe0, 0x21, 0xc0, 0xa7, 0x30, 0x32, 0x64, 0x4c, 0xad, 0x9a, 0x92, 0xbe, 0xb5, 0xb5, 0xa6, 0x60,
0xf0, 0x01, 0x3f, 0x8a, 0xf8, 0x2c, 0x50, 0x67, 0xa0, 0xa0, 0xa6, 0x2f, 0x35, 0x55, 0x46, 0x35,
0x86, 0xe5, 0xbe, 0xb9, 0xa1, 0x63, 0x3c, 0x20, 0xf7, 0x94, 0x4c, 0x7d, 0xd1, 0x90, 0x28, 0x3f,
0x6f, 0x92, 0xc3, 0x45, 0x20, 0xaf, 0x37, 0x16, 0x11, 0x76, 0xdd, 0xbb, 0x8a, 0x86, 0xfa, 0xb5,
0x2b, 0x8a, 0xd6, 0x55, 0x2d, 0xa3, 0x6b, 0x21, 0xc0, 0x7b, 0x30, 0xb8, 0xd0, 0xaa, 0x6b, 0x83,
0x41, 0x05, 0x8f, 0xd1, 0xf2, 0x23, 0xc0, 0xb6, 0x2b, 0x8d, 0x6f, 0xe1, 0xf0, 0xf7, 0x2e, 0xf1,
0xe1, 0xbf, 0x27, 0x35, 0xb9, 0xff, 0xd7, 0xfd, 0x56, 0xf6, 0xb3, 0x5b, 0x9f, 0x06, 0xfe, 0x9f,
0x79, 0xf6, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x10, 0x59, 0xee, 0x46, 0x03, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -332,7 +573,7 @@ type AuthorizerServer interface {
type UnimplementedAuthorizerServer struct { type UnimplementedAuthorizerServer struct {
} }
func (*UnimplementedAuthorizerServer) IsAuthorized(ctx context.Context, req *IsAuthorizedRequest) (*IsAuthorizedReply, error) { func (*UnimplementedAuthorizerServer) IsAuthorized(context.Context, *IsAuthorizedRequest) (*IsAuthorizedReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method IsAuthorized not implemented") return nil, status.Errorf(codes.Unimplemented, "method IsAuthorized not implemented")
} }

View file

@ -37,5 +37,11 @@ message IsAuthorizedReply {
string user = 5; string user = 5;
string email = 6; string email = 6;
repeated string groups = 7; repeated string groups = 7;
HTTPStatus http_status = 8;
} }
message HTTPStatus {
int32 code = 1;
string message = 2;
map<string, string> headers = 3;
}

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.21.0 // protoc-gen-go v1.23.0
// protoc v3.11.4 // protoc v3.12.1
// source: cache.proto // source: cache.proto
package cache package cache

View file

@ -0,0 +1,6 @@
package httputil
// StatusInvalidClientCertificate is the status code returned when a
// client's certificate is invalid. This is the same status code used
// by nginx for this purpose.
const StatusInvalidClientCertificate = 495

22
scripts/protoc Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash
set -euo pipefail
_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
_protoc_version="3.12.1"
_protoc_path="/tmp/pomerium-protoc/protoc-$_protoc_version"
_os="linux"
if [ "$(uname -s)" == "Darwin" ]; then
_os="osx"
fi
if [ ! -f "$_protoc_path" ]; then
echo "downloading protoc"
mkdir -p "/tmp/pomerium-protoc"
curl -L \
-o protoc.zip \
"https://github.com/protocolbuffers/protobuf/releases/download/v$_protoc_version/protoc-$_protoc_version-$_os-x86_64.zip"
unzip -p protoc.zip bin/protoc >"$_protoc_path"
fi
chmod +x "$_protoc_path"
exec "$_protoc_path" --plugin="protoc-gen-go=$_dir/protoc-gen-go" "$@"

3
scripts/protoc-gen-go Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
set -euo pipefail
exec go run github.com/golang/protobuf/protoc-gen-go "$@"