From 3ad8cbf4ec4d87f32b55e80c62e54f983f29b395 Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Wed, 24 Jun 2020 14:00:08 -0600 Subject: [PATCH] authorize: avoid serializing databroker data map to improve performance (#995) --- authorize/evaluator/evaluator.go | 26 ++++-- authorize/evaluator/evaluator_test.go | 85 ++++++++++++++++--- authorize/evaluator/opa/policy/authz.rego | 6 +- .../evaluator/opa/policy/authz_test.rego | 14 ++- authorize/evaluator/opa/policy/statik.go | 2 +- 5 files changed, 104 insertions(+), 29 deletions(-) diff --git a/authorize/evaluator/evaluator.go b/authorize/evaluator/evaluator.go index 7c07a2671..4221a1c30 100644 --- a/authorize/evaluator/evaluator.go +++ b/authorize/evaluator/evaluator.go @@ -30,6 +30,12 @@ import ( "github.com/pomerium/pomerium/internal/log" ) +const ( + sessionTypeURL = "type.googleapis.com/session.Session" + userTypeURL = "type.googleapis.com/user.User" + directoryUserTypeURL = "type.googleapis.com/directory.User" +) + // Evaluator specifies the interface for a policy engine. type Evaluator struct { rego *rego.Rego @@ -202,15 +208,25 @@ func (e *Evaluator) SignedJWT(req *Request) (string, error) { } type input struct { - DataBrokerData DataBrokerData `json:"databroker_data"` - HTTP RequestHTTP `json:"http"` - Session RequestSession `json:"session"` - IsValidClientCertificate bool `json:"is_valid_client_certificate"` + DataBrokerData dataBrokerDataInput `json:"databroker_data"` + HTTP RequestHTTP `json:"http"` + Session RequestSession `json:"session"` + IsValidClientCertificate bool `json:"is_valid_client_certificate"` +} + +type dataBrokerDataInput struct { + Session interface{} `json:"session,omitempty"` + User interface{} `json:"user,omitempty"` + DirectoryUser interface{} `json:"directory_user,omitempty"` } func (e *Evaluator) newInput(req *Request, isValidClientCertificate bool) *input { i := new(input) - i.DataBrokerData = req.DataBrokerData + i.DataBrokerData.Session = req.DataBrokerData.Get(sessionTypeURL, req.Session.ID) + if obj, ok := i.DataBrokerData.Session.(interface{ GetUserId() string }); ok { + i.DataBrokerData.User = req.DataBrokerData.Get(userTypeURL, obj.GetUserId()) + i.DataBrokerData.DirectoryUser = req.DataBrokerData.Get(directoryUserTypeURL, obj.GetUserId()) + } i.HTTP = req.HTTP i.Session = req.Session i.IsValidClientCertificate = isValidClientCertificate diff --git a/authorize/evaluator/evaluator_test.go b/authorize/evaluator/evaluator_test.go index ab45ed035..bad815907 100644 --- a/authorize/evaluator/evaluator_test.go +++ b/authorize/evaluator/evaluator_test.go @@ -1,16 +1,23 @@ package evaluator import ( + "context" "encoding/json" + "fmt" "net/http" "net/url" "testing" + "github.com/golang/protobuf/ptypes" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/pomerium/pomerium/config" + "github.com/pomerium/pomerium/internal/grpc/databroker" "github.com/pomerium/pomerium/internal/grpc/directory" + "github.com/pomerium/pomerium/internal/grpc/session" + "github.com/pomerium/pomerium/internal/grpc/user" ) func TestJSONMarshal(t *testing.T) { @@ -25,7 +32,7 @@ func TestJSONMarshal(t *testing.T) { "type.googleapis.com/user.User": map[string]interface{}{}, } - bs, _ := json.Marshal(input{ + bs, _ := json.Marshal(new(Evaluator).newInput(&Request{ DataBrokerData: dbd, HTTP: RequestHTTP{ Method: "GET", @@ -40,18 +47,9 @@ func TestJSONMarshal(t *testing.T) { ImpersonateEmail: "y@example.com", ImpersonateGroups: []string{"group1"}, }, - IsValidClientCertificate: true, - }) + }, true)) assert.JSONEq(t, `{ "databroker_data": { - "type.googleapis.com/directory.User": { - "user1": { - "id": "user1", - "groups": ["group1", "group2"] - } - }, - "type.googleapis.com/session.Session": {}, - "type.googleapis.com/user.User": {} }, "http": { "client_certificate": "CLIENT_CERTIFICATE", @@ -97,3 +95,68 @@ func mustParseURL(str string) *url.URL { } return u } + +func BenchmarkEvaluator_Evaluate(b *testing.B) { + e, err := New(&config.Options{ + AuthenticateURL: mustParseURL("https://authn.example.com"), + }) + if !assert.NoError(b, err) { + return + } + + lastSessionID := "" + + dbd := make(DataBrokerData) + for i := 0; i < 100; i++ { + sessionID := uuid.New().String() + lastSessionID = sessionID + userID := uuid.New().String() + data, _ := ptypes.MarshalAny(&session.Session{ + Version: fmt.Sprint(i), + Id: sessionID, + UserId: userID, + IdToken: &session.IDToken{ + Issuer: "benchmark", + Subject: userID, + IssuedAt: ptypes.TimestampNow(), + }, + OauthToken: &session.OAuthToken{ + AccessToken: "ACCESS TOKEN", + TokenType: "Bearer", + RefreshToken: "REFRESH TOKEN", + }, + }) + dbd.Update(&databroker.Record{ + Version: fmt.Sprint(i), + Type: "type.googleapis.com/session.Session", + Id: sessionID, + Data: data, + }) + data, _ = ptypes.MarshalAny(&user.User{ + Version: fmt.Sprint(i), + Id: userID, + }) + dbd.Update(&databroker.Record{ + Version: fmt.Sprint(i), + Type: "type.googleapis.com/user.User", + Id: userID, + Data: data, + }) + } + + b.ResetTimer() + ctx := context.Background() + for i := 0; i < b.N; i++ { + e.Evaluate(ctx, &Request{ + DataBrokerData: dbd, + HTTP: RequestHTTP{ + Method: "GET", + URL: "https://example.com/path", + Headers: map[string]string{}, + }, + Session: RequestSession{ + ID: lastSessionID, + }, + }) + } +} diff --git a/authorize/evaluator/opa/policy/authz.rego b/authorize/evaluator/opa/policy/authz.rego index 960fb095b..680af1559 100644 --- a/authorize/evaluator/opa/policy/authz.rego +++ b/authorize/evaluator/opa/policy/authz.rego @@ -4,9 +4,9 @@ default allow = false route := first_allowed_route(input.http.url) -session := input.databroker_data["type.googleapis.com/session.Session"][input.session.id] -user := input.databroker_data["type.googleapis.com/user.User"][session.user_id] -directory_user := input.databroker_data["type.googleapis.com/directory.User"][session.user_id] +session := input.databroker_data.session +user := input.databroker_data.user +directory_user := input.databroker_data.directory_user # allow public diff --git a/authorize/evaluator/opa/policy/authz_test.rego b/authorize/evaluator/opa/policy/authz_test.rego index d3e438ade..87733d16b 100644 --- a/authorize/evaluator/opa/policy/authz_test.rego +++ b/authorize/evaluator/opa/policy/authz_test.rego @@ -7,15 +7,11 @@ test_email_allowed { "allowed_users": ["x@example.com"] }] with input.databroker_data as { - "type.googleapis.com/session.Session": { - "session1": { - "user_id": "user1" - } - }, - "type.googleapis.com/user.User": { - "user1": { - "email": "x@example.com" - } + "session": { + "user_id": "user1" + }, + "user": { + "email": "x@example.com" } } with input.http as { "url": "http://example.com" } with diff --git a/authorize/evaluator/opa/policy/statik.go b/authorize/evaluator/opa/policy/statik.go index 3cf01b1c8..8f729f9f0 100644 --- a/authorize/evaluator/opa/policy/statik.go +++ b/authorize/evaluator/opa/policy/statik.go @@ -9,6 +9,6 @@ import ( const Rego = "rego" // static asset namespace func init() { - data := "PK\x03\x04\x14\x00\x08\x00\x08\x00bo\xd3P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00authz.regoUT\x05\x00\x01\xa9\xc4\xec^\xb4WMs\xdb6\x13>\x13\xbfb\x83\\\xc4\xf7\xa5\xa9\xa4\x1f\x87\xaa\xa3\xba\x99\x9czh\x9dI\x9a\x13\x87a r%\"!\x01\x16\x00k;\xae\xff{g\x01R\x92e\x8bV\xea\xf6b\x91\x8bg\x9f\xfd\xe4b\xdd\x89\xf2\xb3\xd8 t\xbaE#\xfb6\x15\xbd\xab\xbf0V\xe1Z\xf4\x8d\x03\xd14\xfa\x12\x96\xb0\x16\x8dE\xc6\x98\xd1\xbdCX,a-\x8du\x85?\xc6\xaa\xf0\xe2\x99T]\xef\xd2\xda\xb9.\xedM\x133\x8b\xd6J\xad\x08\x1e\x8e*\xe1\xc4\xca\xe8\xcfh\nz\xcc\xb8\xbb\xee0\xddh\xbdiPt\xd2\xa6\xa5n\xe7\x83V\xfa.\xfc\xf2<\x0b\xca\xa3\\V9\xeb-\x9a\xaf\xa4%\x95\xf4\xbdE\xc3\xf3l\xa4\"YA|\x954X:m\xae\x8b\x7f\xc0\xbcU>J\xcf\xd8\xf3!\x93]\xbfjd\xc9\xc2\xcb\x0d\x8b\x885\xf5\xd9+:\xdd\xc8R\xa2\xcd\xfck\x9e\xbe\"\xcc\x1b\x8f\x7f\xaf\xa8,\xa8\x9c,\x85\xc3\xeaUY\xa2\xb5\xb0\\\x823=\xb2\xdb\x1d}\xa9\x8d\x85\xce\xe0\xba\x91\x9b\xda\x9dd\xe6\xf5\xc5\xdbw\xc1\xd4\xa8\xb6%\x8e\xf6\n\xda\xa2\xabuEG\xfc\xe2\xcd\xef\xbf\\\xfc\xf6\x8e\xb3\xa8\xd4\xbdr3\xbd\xfa\x84\xa5K7\xe8\xf6;\xa0FQ\xa1\xb1 \xf0\xe0\xee\xd9k\xad\x9c\xd1\xcd\xd9[\xfc\xa3G\xeb\xce~\xf5\x8c<\x81,\x8fc\xf8 ^\x9c\xcawa\xe4F\xaa}\xc5\xbd\x0c\xac\xae\x01[!\x9b]\xec\xbe\xf0^F\xdeOdblfR\xb0Y\x91\xef\xd3n\x8c\xee\xbb\x1d\xa7\xd5-\x0e\xb2\xe8n\xef\xa4^J\xea\xb0\xdc\"\x1e\xb7y_\xebnL\xb2\xed\xd0X\xad\x84\xc3\xc3\xf8N`\x1f#\x82\xb1\xaf\xb7\xdf\xd2\x8e\xb6\x08\xb4\xc7\xcdN\xa4\xe08\xe9\x7f\x93\x8dJ\xb7B\xaa\x03_\x06a\xe4\xe3(\xa4*\x82`\xb6\xab\x7frJ\xf5\x83\x96\xcd\xc2o\x1eOd\xe4\xab\xdcx$\xf1O\xf6m\x9c\xe0\xd0\x9b\xc6\xee|*\xb5r\xa4s0\x9c\x13\xe0\xf3tT\x99\xf3\x98EJ;8 ,\xaaV*~\xc7\xb6\x1f\x9a\xd2\x82?\xda\xd9\xc6\x06[T\x8e\x92\xd0H\xebf>B\x8f\xb1\xc9\xd0\x88\xbb\xe2\xc4S\xbe\x1e\xb1^\xa1\xba\x06\xa5\xd5\x99\x97z7,\xac\x8dnA\xd0\xcc\x91j\x13\\\x02\x9fG\xcb\x08\x9f\x19\x14V\xab\x9c\x1c\x0c\x8f\xb0\x84\xec\xbb\x17\xdf&\xc0\xc78(\x17\xc1P\x1e\x123\x19\xc9I1<\x1c\xc2\x84C?|\x9f\x00\x97\xeaO\xd1\xc8\n\xcaF\xa2rP\xa2qr\xed/\x01\xf2L\xdab\xa5u\x83b\xec.i\x0b\x8f/\x02\xbe\xd8\xc3\x0f\x15~\x14\x17\x12k\xd0\xf5FYp5\x86\x9b\x1eZ\xe1\xca\x9a\x12\xeaS\xc9\x8e^\xff\x05\xdd\xfc\xb0\x0c0\x1f\xd2\xb81\x84f\x86\xbf\xc0\x7f&\xe1\xe5G\x98\xda \xa6\xbe\x898\xcf^\xf8 }\xc4\x87\x04\xbc\xc2u|3\x8c'\x12\x16z\xf5\x89\\\xe9\x84\xb1H\x82=\x9fYt\x87\xa9\xb0\xba7\xe5\x1e!\xe9nI\x0f\xc1t\xe5\xca\xabS\xc1\xc2\xd5'B\x0dn\xf0(\xeda\xf0\xd3.S-\xf6n\xd6 M\x80\x07%\x9e\x00\xe7\xb1\xbf\xde9\xbb\xfd\xd7y\x9fy\xde(\xc8\x1e\xaeDPL\x03$>(ZZk\xeb\xf7\x92\xbb\x0c^|?\x0f\x93\xd58\xe6oP\x9a\xcc\xc3\xd3y\xc7<8a\x9c\xbd\x94\x87}\x90Rk\x8c\x8ci\xd0|\xa0\xce\x13\x0dt\xd4\x0b\xe1\xea\xe9\xd8\x9e\xc49\xc45:.\\Mf\xee\xc7v?\x96\xa9\x0e?f\xd8\xebLF\xf3T\xd6!\x1e\x83\x85\x9f{cszH\xf2@\\\xbeH\xbb^\xb6\xce\xd0\x0c\xbc\x01n\xcb\x1a[\xe4\x0b\x08\x0f pjY\xbe\x00\xfa\x19s\xb8\x00\x9f\xb1[\xf2,+\x92-6`\x8c\xb8\xa4c\xda\x85\xbc\xfdt-UE\xa3\xb7\xb0\xceH\xb5)l\xbf\xf2^\x16j\xc6\xa2\xe8\xe3\xec|1\xa3 \x9a\xd9\xfc<^\xcc\xe7\xf1\xf9,\xfb0\xcf\xff\x1f\xcf\xb2\x0f\xe7\xcf\xf3\xff\xc5\x1f\x13\x16E\xd6\x99\x04^\xc64D\xa3P/P\xda\xb4\xa2\x91_\xc2\xe7\xe5\x1bb\xb0\xed\xc3{\xe0x\x88\x93\xcf\xb9_\x7f\x9c\xd9\x96\xe38\x98P\x03\xf8\xd9\x00f\x87\xbb\xd2\xb8\x11\xf97_\xb0+\x1a\x16\xb6k\xa4\x1b\x0f\xf9\xcf<\x1e\xffc\xb8\xf2}\xf0\x0d\x8b\xae\xb2\x97\xb9\xdf\xf2\xc3\x12F\xd4\x0777\xfdI\xfc}N\xbc\x00\xf4\x1e\x16M\x92\xb1[\xf6w\x00\x00\x00\xff\xffPK\x07\x08l\xe7g\xc1B\x04\x00\x00\x12\x0f\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00bo\xd3P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00 \x00authz_test.regoUT\x05\x00\x01\xa9\xc4\xec^\xccW]O\xeb8\x10}N~E\xe4\xa7e\xd5&\xe2\xb5\x12Z\x10Z\xad\xf6a\xb7\x88\x8f\xa7\xaa\x8a\xdcdn\xe3K\x12\x07\xdb\x11\x05\xd4\xff~5v>\x9a\xe2\x80\x89@\x97\x17\x12l\xcf\x999\xe7\xcc\x98P\xd1\xe4\x9en!\xa8x\x01\x82\xd5EHk\x95=\xfb\xbe\x02\xa9b((\xcbc\x9a\xe7\xfc\x11\xd2\xe0\xc5\xf7\xf4k\xf0\xc8T\xe6{^J\x15\x0d\x05\xaf\x15\xc4\x15\xcfY\xc2@\x06T\x06\xab\x17\xdf\xf3<\"y-\x12 \x8b\x80\xc0\x8e\x16U\x0ea\xc2\x0b2\xd3{\x0db\\K\x10\x92,\x82\x15\xd9\x9d\x1f\x9eZ\xfb\x9e\xb7_\xb7yXY\xd5*\xc4l\x1b\xc1\xefA\xc4\xf8\x8a\x99L\"\xf5TA\xb8\xe5|\x9b\x03\xad\x98D\x80H\x82\x94\x8c\x97\xe1\x8dy\x92\x859\xeb\x91f\xe3\xb4[\xf1\x08\x16\x11\xb3\x14+\xc5\xd7S\xa2\xd7\xf7\xf8s?\x1b\xcd\x80G\xc3; \xa2\xc76\xd1=\xb0V\x0fa\x87\xe4\x0e\xe0\x91\xe6\x90e\xa6T\xa5\xa9\x05\xa4\x16:\x18W\x16Qt\x88\x10\x1c\x055\xa4\x9a8C\xa5#\x1a\xec\xfd}k\xa7\xc1\xc0\x02K\xae\x02'3\xb1\xceV\xbb\xceQKM3s\xa6\xa2*\xc3\x13\x11mWZ\xafS^PV\x1a\xb7\x8f\xbdn\x84\x9e\x92gs\x9c\xa7\xef\xa9\x92\xf3\x12\xce\xbb\xc6\x1e&[\x7f\\\xf7h\xf3JyL6\x90\xfd\x94\xcc\x82\xde\xf8\x9f\x1c\xce\x87\xc6\xf5^\xe8\xd1J\xa1df\xb2\x9c\x0d\x992]\x1b\xbeyw\xbe\\\x14\xf8D\xfeU\xbd\xc9Y\xf2\x05w\xcb\x05\xc2\\i\xf4\xbb\x12/3(\x15K\xa8\x82\xf4\"I@\xa2 J\xd40]\x01\x7f?`0\xc1Bk\xaf\xdb\x9a\\\xc0\x0f\xb63m\xfe4G\xad\xc7\x9b\xddf\xf1\xd8XYR\xb9\xab\xa6o\xad1\xe5\xb4\x03o\x0cP\xc3\x02\xc5\xef;\xa1\x19\xd0/\xe8\x057\x99\xa6\xf4A\x14\xb6eG\x87-\xd1R\x99\xd0\x14_\xce\xe6\x1dozB4-X\xd9\xe4\xcc\xb8T\xc7\xd5\x0c\xdcK\xb8\x9016j\xce\xb6\x99\xfa=\x1e\x9a\x83\x97\xcb\xeb\x1b\xd3\xc6m5\x0e\xa3\xae#\x0bP\x19\xd7\xd7\xd7\xf2\xea\xf6\xdf\xe5\xff7M\xeaq\xb1Zu\x80\xa6\xa6\xaaf\xc6\x96\x82mY\xa9\xab\x94\xbc\x00n~]\xb7C\xa6Gi~\xc9K%x>\xbf\x86\x87\x1a\xa4\x9a\xff\xd7\xa6_\x91\x7f\xfe\xbem&\xb7\x11\xd9\xa6\xf1\xb7m\xaeo\xacc3\x9fTH\x88k\x91c\x1e|,\xce\x82n\xed\x0f[\x81\x98=\xc2\x8f\x8d\xbf\x1e$9\xd1A\xa1L2( 8;3\x94\x88Y\xc5I\xd1k\xc3Q\xc1-\x8c\xd7[=\x1c\xe9jj\x857\xae\x19\x8b\xba\xf1i\xd7m\xb5\x91Y\xf02b\xe9\xfe\xe4\xe3\xf1\x96\x03Sa\xe4\x14\x9c\xe8\xb3\x80\xde\xc7\x89\xdc\x80\x1c*2H\xdd\x18\x8e\xa2q\xb1}\xdb.{7\x98\x0f\x00\xf7n8\xf8`p\xa4\xa8\xefz\xdd\x96\xba+\x8f@\xcc_\x027\x8a\x96\x1a\xba\xf0\x11v8\x16\xee\xdc\xda/~Gf\x96 '\x12VI\xba\xffj\xa6\x08\xf2*\xd8.\x87\x80-|\xc0k}\x1cq\xc3?\x1d\x15\xb1\x10\xeb@\x9a\xcd\x06\xcb\x9d\\\x07\xb0\xda==\xaf\x0d\xb9_\x01\x00\x00\xff\xffPK\x07\x08.6I;\x1b\x03\x00\x00S\x10\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00bo\xd3Pl\xe7g\xc1B\x04\x00\x00\x12\x0f\x00\x00\n\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00authz.regoUT\x05\x00\x01\xa9\xc4\xec^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00bo\xd3P.6I;\x1b\x03\x00\x00S\x10\x00\x00\x0f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x83\x04\x00\x00authz_test.regoUT\x05\x00\x01\xa9\xc4\xec^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x87\x00\x00\x00\xe4\x07\x00\x00\x00\x00" + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00.\x83\xd8P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00authz.regoUT\x05\x00\x01y~\xf3^\xb4WKs\xdb6\x10>\x13\xbfb\x83\\\xc4\x96\xa6\x9c>\x0eUGu39\xf5\xd0:\x93\xb4'\x8e\xc2@$$\"!\x01\x16\x00k;\xae\xff{g\x17\xa4\xf5\xb0I\xab\xe3\xf6b\x91\x8bo\xbf}r\x17nE\xf1Yl%\xb4\xa6\x91VuM*:_}a\xac\x94\x1b\xd1\xd5\x1eD]\x9b+X\xc2F\xd4N2\xc6\xac\xe9\xbc\x84\xc5\x126\xca:\x9f\xd3\xb1,s\x12\xcf\x94n;\x9fV\xde\xb7ig\xeb\x989\xe9\x9c2\x1a\xe1\xe1\xa8\x14^\xac\xad\xf9,m\x8e\x8fi\x0f`\x9d\x93v\x1c\x85\xa7\xacTV\x16\xde\xd8\x9b|\x1a|\x88c\x8c\xbd\xecch\xbbu\xad\n\x16^nYDh\xf2;oM\xad\n%]F\xaf\xab\xf45b\xde\x12\xfe\x0f\x8d \x91\xda\xabBxY\xbe.\n\xe9\x1c,\x97\xe0m'\xd9\xdd\x8e\xbe0\xd6Ak\xe5\xa6V\xdb\xca\x9fd\xe6\xcd\xe5\xbb\xf7\xc1\xd4\xa0vO\x1c\xed\xa5\xb2\x91\xbe2%\x1e\xf1\xcb\xb7\xbf\xffr\xf9\xdb{\xce\xa2\xc2t\xda\xcf\xcc\xfa\x93,|\xba\x95~?\xf7\x95\x14\xa5\xb4.\x01\x1e\xdc={c\xb4\xb7\xa6>{'\xff\xec\xa4\xf3g\xbf\x12#O [\xc51\xfc\x04\xe7\xa7\xf2]Z\xb5Uz_q/\x03\xeb\x1b\x90\x8dP\xf5.v\xac@J2\xf4~\"\x13C\x1b\xa1\x82\xcb\xf2\xd5>\xed\xd6\x9a\xae\xddq:\xd3\xc8^\x16\x1d\xd6:%)\xaa\xc3\xf2\x1e\xf1\xb4\xcd\x87Z\x871\xa9\xa6\x95\xd6\x19-\xbc<\x8e\xef\x04\xf6!\"\x18\xfa\xb5o\xf9t\x8f6\x0f\xb4\xe3f'R0N\xfa\xffd\xa34\x8dP\xfa\xc8\x97^\x18Q\x1c\xb9\xd2y\x10\xccv\xf5ON\xa9~\xd0rY\xf8]\xc5\x13\x19\xf9Wn<\x91\xf8g\xfb6\xccN\xe8l\xedv>\x15F{\xd49\x1a\x8b \xf0y:\xa8\xccy\xcc\"m<\x9c\x04\x16e\xa34?\xb0M\xc3P9\xa0\xa3\x9dmY\xcbFj\x8fI\xa8\x95\xf33\x8a\x900.\xe9\x1bqW\x9cx\xca\xd7\x11\xeb\xa5\xd47\xa0\x8d>#)\xb9\xe1`cM\x03\x02g\x8e\xd2\xdb\xe0\x12P\x1e\x1dC|f\xa5pF\xaf\xd0\xc1\xf0\x08K\xc8\xbe;\xff6\x01>\xc4\x81\xb9\x08\x86V!1\x93\x91\x9c\x14\xc3\xe3!L8\xf4\xc3\xf7 p\xa5\xff\x12\xb5*\xa1\xa8\x95\xd4\x1e\ni\xbd\xda\xd0\x12@\xcf\x94\xcb\xd7\xc6\xd4R\x0c\xdd\xa5\\N\xf8<\xe0\xf3=|_\xe1'q!\xb1V\xfa\xcej\x07\xbe\x92a\xc7B#|QaB)\x95lt\xf1\xe6\xb8sa\x19`\x14\xd2\xb0\xabC3\xc3\xdf@\x9fIx\xf9\x11\xa6v\xf7\xd47\x11\xaf\xb2s\x9a\xd0#>$@\n7\xf1m?\x9eP\x98\x9b\xf5't\xa5\x15\xd6I\x14\xec\xf9\xcc\xa2\x03\xa6\xdc\x99\xce\x16{\x84\xa8{Oz\x0c\xc6\x95\xab\xaeO\x05\x0b_\x9d\x08\xb5r+Gi\x8f\x83\x9fv\x19k\xb1\xb7Y\x834\x01\x1e\x94x\x02\x9c\xc7\xb4\xde9\xbb\xfb\xcfy_\x10o\x14d\x8fW\"(\xa6\x01\x12\x1f\x15-\xad\x8c\xa3{\xc9!\x03\x89\x1f\xe6a\xb2\x1ac\xfe\x06\xa5\xc9<<\x9fw\xc8\x83\x17\xd6\xbb+u\xdc\x07)\xb6\xc6\xc0\x98\x06\xcdG\xea<\xd1@\xa3^\x08_M\xc7\xf6,\xce>\xae\xc1q\xe1+4\xf30\xb6\x87\xb1Lu\xf8\x98a\xd2\x99\x8c\xe6\xb9\xac}\x9a\xe2\x80\x89@\x97\x17\x12l\xcf\x999\xe7\xcc\x98P\xd1\xe4\x9en!\xa8x\x01\x82\xd5EHk\x95=\xfb\xbe\x02\xa9b((\xcbc\x9a\xe7\xfc\x11\xd2\xe0\xc5\xf7\xf4k\xf0\xc8T\xe6{^J\x15\x0d\x05\xaf\x15\xc4\x15\xcfY\xc2@\x06T\x06\xab\x17\xdf\xf3<\"y-\x12 \x8b\x80\xc0\x8e\x16U\x0ea\xc2\x0b2\xd3{\x0db\\K\x10\x92,\x82\x15\xd9\x9d\x1f\x9eZ\xfb\x9e\xb7_\xb7yXY\xd5*\xc4l\x1b\xc1\xefA\xc4\xf8\x8a\x99L\"\xf5TA\xb8\xe5|\x9b\x03\xad\x98D\x80H\x82\x94\x8c\x97\xe1\x8dy\x92\x859\xeb\x91f\xe3\xb4[\xf1\x08\x16\x11\xb3\x14+\xc5\xd7S\xa2\xd7\xf7\xf8s?\x1b\xcd\x80G\xc3; \xa2\xc76\xd1=\xb0V\x0fa\x87\xe4\x0e\xe0\x91\xe6\x90e\xa6T\xa5\xa9\x05\xa4\x16:\x18W\x16Qt\x88\x10\x1c\x055\xa4\x9a8C\xa5#\x1a\xec\xfd}k\xa7\xc1\xc0\x02K\xae\x02'3\xb1\xceV\xbb\xceQKM3s\xa6\xa2*\xc3\x13\x11mWZ\xafS^PV\x1a\xb7\x8f\xbdn\x84\x9e\x92gs\x9c\xa7\xef\xa9\x92\xf3\x12\xce\xbb\xc6\x1e&[\x7f\\\xf7h\xf3JyL6\x90\xfd\x94\xcc\x82\xde\xf8\x9f\x1c\xce\x87\xc6\xf5^\xe8\xd1J\xa1df\xb2\x9c\x0d\x992]\x1b\xbeyw\xbe\\\x14\xf8D\xfeU\xbd\xc9Y\xf2\x05w\xcb\x05\xc2\\i\xf4\xbb\x12/3(\x15K\xa8\x82\xf4\"I@\xa2 J\xd40]\x01\x7f?`0\xc1Bk\xaf\xdb\x9a\\\xc0\x0f\xb63m\xfe4G\xad\xc7\x9b\xddf\xf1\xd8XYR\xb9\xab\xa6o\xad1\xe5\xb4\x03o\x0cP\xc3\x02\xc5\xef;\xa1\x19\xd0/\xe8\x057\x99\xa6\xf4A\x14\xb6eG\x87-\xd1R\x99\xd0\x14_\xce\xe6\x1dozB4-X\xd9\xe4\xcc\xb8T\xc7\xd5\x0c\xdcK\xb8\x9016j\xce\xb6\x99\xfa=\x1e\x9a\x83\x97\xcb\xeb\x1b\xd3\xc6m5\x0e\xa3\xae#\x0bP\x19\xd7\xd7\xd7\xf2\xea\xf6\xdf\xe5\xff7M\xeaq\xb1Zu\x80\xa6\xa6\xaaf\xc6\x96\x82mY\xa9\xab\x94\xbc\x00n~]\xb7C\xa6Gi~\xc9K%x>\xbf\x86\x87\x1a\xa4\x9a\xff\xd7\xa6_\x91\x7f\xfe\xbem&\xb7\x11\xd9\xa6\xf1\xb7m\xaeo\xacc3\x9fTH\x88k\x91c\x1e|,\xce\x82n\xed\x0f[\x81\x98=\xc2\x8f\x8d\xbf\x1e$9\xd1A\xa1L2( 8;3\x94\x88Y\xc5I\xd1k\xc3Q\xc1-\x8c\xd7[=\x1c\xe9jj\x857\xae\x19\x8b\xba\xf1i\xd7m\xb5\x91Y\xf02b\xe9\xfe\xe4\xe3\xf1\x96\x03Sa\xe4\x14\x9c\xe8\xb3\x80\xde\xc7\x89\xdc\x80\x1c*2H\xdd\x18\x8e\xa2q\xb1}\xdb.{7\x98\x0f\x00\xf7n8\xf8`p\xa4\xa8\xefz\xdd\x96\xba+\x8f@\xcc_\x027\x8a\x96\x1a\xba\xf0\x11v8\x16\xee\xdc\xda/~Gf\x96 '\x12VI\xba\xffj\xa6\x08\xf2*\xd8.\x87\x80-|\xc0k}\x1cq\xc3?\x1d\x15\xb1\x10\xeb@\x9a\xcd\x06\xcb\x9d\\\x07\xb0\xda==\xaf\x0d\xb9_\x01\x00\x00\xff\xffPK\x07\x08.6I;\x1b\x03\x00\x00S\x10\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00.\x83\xd8Pr\xb6\xf5+\x18\x04\x00\x00\x8c\x0e\x00\x00\n\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00authz.regoUT\x05\x00\x01y~\xf3^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00bo\xd3P.6I;\x1b\x03\x00\x00S\x10\x00\x00\x0f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81Y\x04\x00\x00authz_test.regoUT\x05\x00\x01\xa9\xc4\xec^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x87\x00\x00\x00\xba\x07\x00\x00\x00\x00" fs.RegisterWithNamespace("rego", data) }