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).
package authorize
//go:generate ../scripts/protoc -I ../internal/grpc/authorize/ --go_out=plugins=grpc:../internal/grpc/authorize/ ../internal/grpc/authorize/authorize.proto
import (
"context"
"encoding/base64"
"fmt"
"html/template"
"io/ioutil"
"sync/atomic"
"github.com/pomerium/pomerium/authorize/evaluator"
@ -14,6 +18,7 @@ import (
"github.com/pomerium/pomerium/internal/cryptutil"
"github.com/pomerium/pomerium/internal/encoding"
"github.com/pomerium/pomerium/internal/encoding/jws"
"github.com/pomerium/pomerium/internal/frontend"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry/metrics"
"github.com/pomerium/pomerium/internal/telemetry/trace"
@ -51,6 +56,7 @@ type Authorize struct {
currentOptions atomicOptions
currentEncoder atomicMarshalUnmarshaler
templates *template.Template
}
// 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 {
return nil, fmt.Errorf("authorize: bad options: %w", err)
}
var a Authorize
a := Authorize{
templates: template.Must(frontend.NewTemplates()),
}
var host string
if opts.AuthenticateURL != nil {
@ -117,12 +125,28 @@ func newPolicyEvaluator(opts *config.Options) (evaluator.Evaluator, error) {
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{}{
"shared_key": opts.SharedKey,
"route_policies": opts.Policies,
"admins": opts.Administrators,
"signing_key": jwk,
"authenticate_url": opts.AuthenticateURLString,
"client_ca": clientCA,
}
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.
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
}
@ -44,6 +44,11 @@ type Request struct {
// It is an error to set this field in an HTTP client request.
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
//
// 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
// decisions.
@ -6,9 +7,11 @@ package opa
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"strconv"
"sync"
"github.com/open-policy-agent/opa/rego"
@ -37,6 +40,7 @@ type PolicyEvaluator struct {
mu sync.RWMutex
store storage.Store
isAuthorized rego.PreparedEvalQuery
clientCA string
}
// 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.
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")
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
@ -110,6 +114,11 @@ func (pe *PolicyEvaluator) PutData(ctx context.Context, data map[string]interfac
pe.mu.Lock()
defer pe.mu.Unlock()
if ca, ok := data["client_ca"].(string); ok {
pe.clientCA = ca
}
txn, err := pe.store.NewTransaction(ctx, storage.WriteParams)
if err != nil {
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 {
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
}
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()
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))
if err != nil {
return nil, fmt.Errorf("eval query: %w", err)
@ -199,3 +244,35 @@ func readPolicy(fn string) ([]byte, error) {
defer r.Close()
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"
"time"
"github.com/pomerium/pomerium/config"
"github.com/stretchr/testify/assert"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
"github.com/pomerium/pomerium/authorize/evaluator"
"github.com/pomerium/pomerium/config"
)
func Test_Eval(t *testing.T) {
@ -89,11 +92,7 @@ func Test_Eval(t *testing.T) {
if err != nil {
t.Fatal(err)
}
req := struct {
Host string `json:"host,omitempty"`
URL string `json:"url,omitempty"`
User string `json:"user,omitempty"`
}{
req := &evaluator.Request{
Host: tt.route,
URL: "https://" + tt.route,
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
http_status = [495, "invalid client certificate"]{
not input.is_valid_client_certificate
}
# allow public
allow {
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_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"
)
@ -67,6 +66,7 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v2.CheckRe
RequestURI: requestURL.String(),
RemoteAddr: in.GetAttributes().GetSource().GetAddress().String(),
URL: requestURL.String(),
ClientCertificate: getPeerCertificate(in),
}
reply, err := a.pe.IsAuthorized(ctx, req)
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.Str("email", reply.GetEmail())
evt = evt.Strs("groups", reply.GetGroups())
if sess != nil {
evt = evt.Str("session", string(sess))
}
if reply.GetHttpStatus() != nil {
evt = evt.Interface("http_status", reply.GetHttpStatus())
}
evt.Msg("authorize check")
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 {
return &envoy_service_auth_v2.CheckResponse{
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()
}
// all other errors
return &envoy_service_auth_v2.CheckResponse{
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
return a.deniedResponse(in, http.StatusForbidden, msg, nil), nil
}
// no redirect for forward auth, that's handled by a separate config setting
if isForwardAuth {
return &envoy_service_auth_v2.CheckResponse{
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
return a.deniedResponse(in, http.StatusUnauthorized, "Unauthenticated", nil), nil
}
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()
redirectTo := urlutil.NewSignedURL(opts.SharedKey, signinURL).String()
return &envoy_service_auth_v2.CheckResponse{
Status: &status.Status{
Code: int32(codes.Unauthenticated),
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
return a.deniedResponse(in, http.StatusFound, "Login", map[string]string{
"Location": redirectTo,
}), nil
}
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
}
// 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

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
import (
@ -12,6 +10,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/cryptutil"
"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 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
}
@ -562,6 +567,18 @@ func (o *Options) Validate() error {
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)
err = AutocertManager.update(o)

View file

@ -209,6 +209,15 @@ certificates:
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
- 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/mux v1.7.4
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/lithammer/shortuuid/v3 v3.0.4
github.com/mitchellh/hashstructure v1.0.0

View file

@ -9,6 +9,6 @@ import (
const Luascripts = "luascripts" // static asset namespace
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)
}

View file

@ -1,6 +1,7 @@
package controlplane
import (
"encoding/base64"
"sort"
"time"
@ -164,6 +165,7 @@ func (srv *Server) buildMainHTTPConnectionManagerFilter(options *config.Options,
},
},
},
IncludePeerCertificate: true,
})
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
}
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)
return &envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{
CommonTlsContext: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext{
TlsCertificates: []*envoy_extensions_transport_sockets_tls_v3.TlsCertificate{envoyCert},
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.
// versions:
// protoc-gen-go v1.23.0
// protoc v3.12.1
// source: authorize.proto
package authorize
import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
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.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// 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
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type IsAuthorizedRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// User Context
//
UserToken string `protobuf:"bytes,1,opt,name=user_token,json=userToken,proto3" json:"user_token,omitempty"`
@ -43,252 +52,484 @@ type IsAuthorizedRequest struct {
// 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"`
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 (m *IsAuthorizedRequest) String() string { return proto.CompactTextString(m) }
func (x *IsAuthorizedRequest) Reset() {
*x = IsAuthorizedRequest{}
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) {
return fileDescriptor_ffbc3c71370bee9a, []int{0}
return file_authorize_proto_rawDescGZIP(), []int{0}
}
func (m *IsAuthorizedRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IsAuthorizedRequest.Unmarshal(m, b)
}
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
func (x *IsAuthorizedRequest) GetUserToken() string {
if x != nil {
return x.UserToken
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestMethod() string {
if m != nil {
return m.RequestMethod
func (x *IsAuthorizedRequest) GetRequestMethod() string {
if x != nil {
return x.RequestMethod
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestUrl() string {
if m != nil {
return m.RequestUrl
func (x *IsAuthorizedRequest) GetRequestUrl() string {
if x != nil {
return x.RequestUrl
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestHost() string {
if m != nil {
return m.RequestHost
func (x *IsAuthorizedRequest) GetRequestHost() string {
if x != nil {
return x.RequestHost
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestRequestUri() string {
if m != nil {
return m.RequestRequestUri
func (x *IsAuthorizedRequest) GetRequestRequestUri() string {
if x != nil {
return x.RequestRequestUri
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestRemoteAddr() string {
if m != nil {
return m.RequestRemoteAddr
func (x *IsAuthorizedRequest) GetRequestRemoteAddr() string {
if x != nil {
return x.RequestRemoteAddr
}
return ""
}
func (m *IsAuthorizedRequest) GetRequestHeaders() map[string]*IsAuthorizedRequest_Headers {
if m != nil {
return m.RequestHeaders
func (x *IsAuthorizedRequest) GetRequestHeaders() map[string]*IsAuthorizedRequest_Headers {
if x != nil {
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
}
// headers represents key-value pairs in an HTTP header; map[string][]string
type IsAuthorizedRequest_Headers struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value []string `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IsAuthorizedRequest_Headers) Reset() { *m = IsAuthorizedRequest_Headers{} }
func (m *IsAuthorizedRequest_Headers) String() string { return proto.CompactTextString(m) }
func (x *IsAuthorizedRequest_Headers) Reset() {
*x = IsAuthorizedRequest_Headers{}
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) {
return fileDescriptor_ffbc3c71370bee9a, []int{0, 0}
return file_authorize_proto_rawDescGZIP(), []int{0, 0}
}
func (m *IsAuthorizedRequest_Headers) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IsAuthorizedRequest_Headers.Unmarshal(m, b)
}
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
func (x *IsAuthorizedRequest_Headers) GetValue() []string {
if x != nil {
return x.Value
}
return nil
}
type IsAuthorizedReply struct {
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"`
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"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
var File_authorize_proto protoreflect.FileDescriptor
var file_authorize_proto_rawDesc = []byte{
0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x22, 0xe8, 0x03, 0x0a,
0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6d,
0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71,
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{} }
func (m *IsAuthorizedReply) String() string { return proto.CompactTextString(m) }
func (*IsAuthorizedReply) ProtoMessage() {}
func (*IsAuthorizedReply) Descriptor() ([]byte, []int) {
return fileDescriptor_ffbc3c71370bee9a, []int{1}
var (
file_authorize_proto_rawDescOnce sync.Once
file_authorize_proto_rawDescData = file_authorize_proto_rawDesc
)
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 {
return xxx_messageInfo_IsAuthorizedReply.Unmarshal(m, b)
var file_authorize_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
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) {
return xxx_messageInfo_IsAuthorizedReply.Marshal(b, m, deterministic)
}
func (m *IsAuthorizedReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_IsAuthorizedReply.Merge(m, src)
}
func (m *IsAuthorizedReply) XXX_Size() int {
return xxx_messageInfo_IsAuthorizedReply.Size(m)
}
func (m *IsAuthorizedReply) XXX_DiscardUnknown() {
xxx_messageInfo_IsAuthorizedReply.DiscardUnknown(m)
var file_authorize_proto_depIdxs = []int32{
4, // 0: authorize.IsAuthorizedRequest.request_headers:type_name -> authorize.IsAuthorizedRequest.RequestHeadersEntry
2, // 1: authorize.IsAuthorizedReply.http_status:type_name -> authorize.HTTPStatus
5, // 2: authorize.HTTPStatus.headers:type_name -> authorize.HTTPStatus.HeadersEntry
3, // 3: authorize.IsAuthorizedRequest.RequestHeadersEntry.value:type_name -> authorize.IsAuthorizedRequest.Headers
0, // 4: authorize.Authorizer.IsAuthorized:input_type -> authorize.IsAuthorizedRequest
1, // 5: authorize.Authorizer.IsAuthorized:output_type -> authorize.IsAuthorizedReply
5, // [5:6] is the sub-list for method output_type
4, // [4:5] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
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 (m *IsAuthorizedReply) GetAllow() bool {
if m != nil {
return m.Allow
}
return false
}
func (m *IsAuthorizedReply) GetSessionExpired() bool {
if m != nil {
return m.SessionExpired
}
return false
}
func (m *IsAuthorizedReply) GetDenyReasons() []string {
if m != nil {
return m.DenyReasons
func init() { file_authorize_proto_init() }
func file_authorize_proto_init() {
if File_authorize_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_authorize_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IsAuthorizedRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
func (m *IsAuthorizedReply) GetSignedJwt() string {
if m != nil {
return m.SignedJwt
}
return ""
}
func (m *IsAuthorizedReply) GetUser() string {
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
}
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
}
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,
}
}
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
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_authorize_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_authorize_proto_goTypes,
DependencyIndexes: file_authorize_proto_depIdxs,
MessageInfos: file_authorize_proto_msgTypes,
}.Build()
File_authorize_proto = out.File
file_authorize_proto_rawDesc = nil
file_authorize_proto_goTypes = nil
file_authorize_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
@ -332,7 +573,7 @@ type AuthorizerServer interface {
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")
}

View file

@ -37,5 +37,11 @@ message IsAuthorizedReply {
string user = 5;
string email = 6;
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.
// versions:
// protoc-gen-go v1.21.0
// protoc v3.11.4
// protoc-gen-go v1.23.0
// protoc v3.12.1
// source: cache.proto
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 "$@"