From 0257280a2aa62333c4deb0a154c396f606a81538 Mon Sep 17 00:00:00 2001 From: Denis Issoupov Date: Thu, 20 May 2021 12:09:27 -0700 Subject: [PATCH] authz: added gRPC support --- .VERSION | 2 +- go.mod | 5 +- go.sum | 70 ++++++++++++++++++++++++++-- xhttp/authz/authz.go | 94 +++++++++++++++++++++++++++++++++----- xhttp/authz/authz_test.go | 39 ++++++++++++++-- xhttp/identity/ctx.go | 36 ++++++++++++++- xhttp/identity/ctx_test.go | 48 +++++++++++++++++++ xhttp/identity/identity.go | 3 ++ 8 files changed, 271 insertions(+), 26 deletions(-) diff --git a/.VERSION b/.VERSION index 4ea1309..e355fa5 100644 --- a/.VERSION +++ b/.VERSION @@ -1 +1 @@ -v0.5 \ No newline at end of file +v0.6 \ No newline at end of file diff --git a/go.mod b/go.mod index bc1810e..b6a818a 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,12 @@ module github.com/go-phorce/dolly go 1.16 require ( - github.com/BurntSushi/toml v0.3.1 // indirect github.com/DataDog/datadog-go v0.0.0-20180330214955-e67964b4021a github.com/GeertJohan/go.rice v1.0.0 // indirect github.com/cloudflare/cfssl v0.0.0-20181102015659-ea4033a214e7 github.com/go-phorce/cov-report v1.1.1-0.20200622030546-3fb510c4b1ba github.com/go-sql-driver/mysql v1.5.0 // indirect - github.com/golang/protobuf v1.3.3 // indirect github.com/google/certificate-transparency-go v1.0.21 // indirect - github.com/google/go-cmp v0.4.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 // indirect @@ -26,7 +23,6 @@ require ( github.com/mattn/goveralls v0.0.6 github.com/miekg/pkcs11 v1.0.3 github.com/prometheus/client_golang v1.1.0 - github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect github.com/prometheus/procfs v0.0.4 // indirect github.com/rs/cors v1.6.0 github.com/stretchr/objx v0.2.0 // indirect @@ -37,6 +33,7 @@ require ( golang.org/x/mod v0.3.0 // indirect golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb + google.golang.org/grpc v1.37.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect diff --git a/go.sum b/go.sum index a3d297a..b234c42 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v0.0.0-20180330214955-e67964b4021a h1:zpQSzEApXM0qkXcpdjeJ4OpnBWhD/X8zT/iT1wYLiVU= @@ -16,13 +17,20 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20181102015659-ea4033a214e7 h1:ROpiky+uT1fstFCMZCka5Cr9GmtpTakLMmvwFsVOtJA= github.com/cloudflare/cfssl v0.0.0-20181102015659-ea4033a214e7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -33,17 +41,29 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= @@ -124,6 +144,7 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= @@ -136,6 +157,10 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -144,7 +169,11 @@ golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -153,10 +182,13 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -164,7 +196,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -174,6 +211,28 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -184,8 +243,11 @@ gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3M gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3 h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI= gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/xhttp/authz/authz.go b/xhttp/authz/authz.go index 3bee472..4e090b8 100644 --- a/xhttp/authz/authz.go +++ b/xhttp/authz/authz.go @@ -29,6 +29,7 @@ package authz import ( "bytes" + "context" "fmt" "io" "net/http" @@ -42,6 +43,9 @@ import ( "github.com/go-phorce/dolly/xlog" "github.com/jinzhu/copier" "github.com/juju/errors" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var logger = xlog.NewPackageLogger("github.com/go-phorce/dolly", "authz") @@ -53,6 +57,40 @@ var ( ErrNoPathsConfigured = errors.New("you must have at least one path before being able to create a http.Handler") ) +// Authz represents an Authorization provider interface, +// You can call Allow or AllowAny to specify which roles are allowed +// access to which path segments. +// once configured you can create a http.Handler that enforces that +// configuration for you by calling NewHandler +type Authz interface { + // SetRoleMapper configures the function that provides the mapping from an HTTP request to a role name + SetRoleMapper(func(*http.Request) string) + // NewHandler returns a http.Handler that enforces the current authorization configuration + // The handler has its own copy of the configuration changes to the Provider after calling + // NewHandler won't affect previously created Handlers. + // The returned handler will extract the role and verify that the role has access to the + // URI being request, and either return an error, or pass the request on to the supplied + // delegate handler + NewHandler(delegate http.Handler) (http.Handler, error) +} + +// GRPCAuthz represents an Authorization provider interface, +// You can call Allow or AllowAny to specify which roles are allowed +// access to which path segments. +// once configured you can create a Unary interceptor that enforces that +// configuration for you by calling NewUnaryInterceptor +type GRPCAuthz interface { + // SetGRPCRoleMapper configures the function that provides + // the mapping from a gRPC request to a role name + SetGRPCRoleMapper(m func(ctx context.Context) string) + // NewUnaryInterceptor returns grpc.UnaryServerInterceptor that enforces the current + // authorization configuration. + // The returned interceptor will extract the role and verify that the role has access to the + // URI being request, and either return an error, or pass the request on to the supplied + // delegate handler + NewUnaryInterceptor() grpc.UnaryServerInterceptor +} + // Config contains configuration for the authorization module type Config struct { // Allow will allow the specified roles access to this path and its children, in format: ${path}:${role},${role} @@ -80,9 +118,10 @@ type Config struct { // once configured you can create a http.Handler that enforces that // configuration for you by calling NewHandler type Provider struct { - roleMapper func(r *http.Request) string - pathRoot *pathNode - cfg *Config + requestRoleMapper func(*http.Request) string + grpcRoleMapper func(context.Context) string + pathRoot *pathNode + cfg *Config } type allowTypes int8 @@ -117,11 +156,23 @@ var defaultRoleMapper = func(r *http.Request) string { return identity.GuestRoleName } +var defaultGrpcRoleMapper = func(ctx context.Context) string { + rt := identity.FromContext(ctx) + if rt != nil { + id := rt.Identity() + if id != nil { + return id.Role() + } + } + return identity.GuestRoleName +} + // New returns new Authz provider func New(cfg *Config) (*Provider, error) { az := &Provider{ - cfg: cfg, - roleMapper: defaultRoleMapper, + cfg: cfg, + requestRoleMapper: defaultRoleMapper, + grpcRoleMapper: defaultGrpcRoleMapper, } for _, s := range cfg.AllowAny { @@ -244,9 +295,10 @@ func (n *pathNode) allowRole(r string) bool { // Clone returns a deep copy of this Provider func (c *Provider) Clone() *Provider { p := &Provider{ - roleMapper: c.roleMapper, - pathRoot: c.pathRoot.clone(), - cfg: &Config{}, + requestRoleMapper: c.requestRoleMapper, + grpcRoleMapper: c.grpcRoleMapper, + pathRoot: c.pathRoot.clone(), + cfg: &Config{}, } copier.Copy(p.cfg, c.cfg) @@ -256,7 +308,12 @@ func (c *Provider) Clone() *Provider { // SetRoleMapper configures the function that provides the mapping from an HTTP request to a role name func (c *Provider) SetRoleMapper(m func(r *http.Request) string) { - c.roleMapper = m + c.requestRoleMapper = m +} + +// SetGRPCRoleMapper configures the function that provides the mapping from a gRPC request to a role name +func (c *Provider) SetGRPCRoleMapper(m func(ctx context.Context) string) { + c.grpcRoleMapper = m } // AllowAny will allow any authenticated request access to this path and its children @@ -353,7 +410,7 @@ func (c *Provider) checkAccess(r *http.Request) error { return nil } - role := c.roleMapper(r) + role := c.requestRoleMapper(r) if role == "" { role = identity.GuestRoleName } @@ -371,7 +428,7 @@ func (c *Provider) checkAccess(r *http.Request) error { // URI being request, and either return an error, or pass the request on to the supplied // delegate handler func (c *Provider) NewHandler(delegate http.Handler) (http.Handler, error) { - if c.roleMapper == nil { + if c.requestRoleMapper == nil { return nil, errors.Trace(ErrNoRoleMapperSpecified) } if c.pathRoot == nil { @@ -398,3 +455,18 @@ func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { marshal.WriteJSON(w, r, httperror.WithUnauthorized(err.Error())) } } + +// NewUnaryInterceptor returns grpc.UnaryServerInterceptor to check access +func (c *Provider) NewUnaryInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + role := c.grpcRoleMapper(ctx) + if role == "" { + role = identity.GuestRoleName + } + if !c.isAllowed(info.FullMethod, role) { + return nil, status.Errorf(codes.PermissionDenied, "the %q role is not allowed", role) + } + + return handler(ctx, req) + } +} diff --git a/xhttp/authz/authz_test.go b/xhttp/authz/authz_test.go index 0ed1d6e..00e4940 100644 --- a/xhttp/authz/authz_test.go +++ b/xhttp/authz/authz_test.go @@ -2,17 +2,18 @@ package authz import ( "bytes" + "context" "net/http" "net/http/httptest" "sort" "testing" - "github.com/go-phorce/dolly/xlog" - "github.com/go-phorce/dolly/xhttp/header" + "github.com/go-phorce/dolly/xlog" "github.com/juju/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/grpc" ) func Test_NewConfig(t *testing.T) { @@ -286,8 +287,8 @@ func TestConfig_Clone(t *testing.T) { c.Allow("/", "bob") clone := c.Clone() c.Allow("/foo", "alice") - require.NotNil(t, clone.roleMapper, "Config.Clone() didn't clone roleMapper") - assert.Equal(t, "bob", clone.roleMapper(nil), "Config.Clone() has a roleMapper set, but it doesn't appear to be ours!") + require.NotNil(t, clone.requestRoleMapper, "Config.Clone() didn't clone roleMapper") + assert.Equal(t, "bob", clone.requestRoleMapper(nil), "Config.Clone() has a roleMapper set, but it doesn't appear to be ours!") assert.False(t, clone.isAllowed("/foo", "alice"), "Config.Clone() returns a clone that was mutated by mutating the original instance (should be a deep copy)") assert.True(t, clone.isAllowed("/foo", "bob"), "Config.Clone() return a clone that's missing an Allow() from the source") } @@ -366,6 +367,36 @@ func TestConfig_Handler(t *testing.T) { testHandler("/", false) } +func TestNewUnaryInterceptor(t *testing.T) { + c, err := New(&Config{ + AllowAny: []string{ + "/pb.Service/method1", + }, + Allow: []string{ + "/pb.Service/method2:bob", + }, + }) + require.NoError(t, err) + + unary := c.NewUnaryInterceptor() + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + } + + si := &grpc.UnaryServerInfo{ + FullMethod: "/pb.Service/method1", + } + _, err = unary(context.Background(), nil, si, handler) + require.NoError(t, err) + + si = &grpc.UnaryServerInfo{ + FullMethod: "/pb.Service/method2", + } + _, err = unary(context.Background(), nil, si, handler) + require.Error(t, err) + assert.Equal(t, `rpc error: code = PermissionDenied desc = the "guest" role is not allowed`, err.Error()) +} + func testHTTPHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("Hello")) diff --git a/xhttp/identity/ctx.go b/xhttp/identity/ctx.go index cfc768d..8fa6cb2 100644 --- a/xhttp/identity/ctx.go +++ b/xhttp/identity/ctx.go @@ -13,6 +13,9 @@ import ( "github.com/go-phorce/dolly/xhttp/httperror" "github.com/go-phorce/dolly/xhttp/marshal" "github.com/go-phorce/dolly/xlog" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var logger = xlog.NewPackageLogger("github.com/go-phorce/dolly", "xhttp/context") @@ -28,8 +31,9 @@ const ( type NodeInfoFactory func() netutil.NodeInfo var ( - nodeInfoFactory = newNodeInfoFactory() - identityMapper Mapper = GuestIdentityMapper + nodeInfoFactory = newNodeInfoFactory() + identityMapper Mapper = GuestIdentityMapper + gRPCIdentityMapper MapperFromContext = nil ) // RequestContext represents user contextual information about a request being processed by the server, @@ -97,6 +101,11 @@ func SetGlobalIdentityMapper(e Mapper) { identityMapper = e } +// SetGlobalGRPCIdentityMapper applies global IdentityMapper for the application +func SetGlobalGRPCIdentityMapper(e MapperFromContext) { + gRPCIdentityMapper = e +} + //FromContext extracts the RequestContext stored inside a go context. Returns null if no such value exists. func FromContext(ctx context.Context) *RequestContext { ret, _ := ctx.Value(keyContext).(*RequestContext) @@ -164,6 +173,29 @@ func NewContextHandler(delegate http.Handler) http.Handler { return http.HandlerFunc(h) } +var grpcGuestIdentity = NewIdentity(GuestRoleName, "", "") + +// NewAuthUnaryInterceptor returns grpc.UnaryServerInterceptor that +// identity to the context +func NewAuthUnaryInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + var id Identity + if gRPCIdentityMapper != nil { + var err error + id, err = gRPCIdentityMapper(ctx) + if err != nil { + return nil, status.Errorf(codes.PermissionDenied, "unable to get identity: %v", err) + } + } + if id == nil { + id = grpcGuestIdentity + } + ctx = AddToContext(ctx, NewRequestContext(id)) + + return handler(ctx, req) + } +} + // Identity returns request's identity func (c *RequestContext) Identity() Identity { return c.identity diff --git a/xhttp/identity/ctx_test.go b/xhttp/identity/ctx_test.go index bc9b9bc..f5a1e85 100644 --- a/xhttp/identity/ctx_test.go +++ b/xhttp/identity/ctx_test.go @@ -25,6 +25,8 @@ func TestMain(m *testing.M) { func Test_SetGlobal(t *testing.T) { assert.Panics(t, func() { SetGlobalIdentityMapper(nil) }) assert.Panics(t, func() { SetGlobalNodeInfo(nil) }) + + assert.NotPanics(t, func() { SetGlobalGRPCIdentityMapper(nil) }) } func Test_Identity(t *testing.T) { @@ -137,6 +139,52 @@ func Test_FromContext(t *testing.T) { }) } +func Test_grpcFromContext(t *testing.T) { + unary := NewAuthUnaryInterceptor() + + t.Run("default_guest", func(t *testing.T) { + unary(context.Background(), nil, nil, func(ctx context.Context, req interface{}) (interface{}, error) { + rt := FromContext(ctx) + require.NotNil(t, rt) + require.NotNil(t, rt.Identity()) + assert.Equal(t, "guest", rt.Identity().Role()) + return nil, nil + }) + }) + + t.Run("with_custom_id", func(t *testing.T) { + def := func(ctx context.Context) (Identity, error) { + return NewIdentity("test", "", ""), nil + } + SetGlobalGRPCIdentityMapper(def) + // restore + defer SetGlobalGRPCIdentityMapper(nil) + + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + rt := FromContext(ctx) + require.NotNil(t, rt) + require.NotNil(t, rt.Identity()) + assert.Equal(t, "test", rt.Identity().Role()) + return nil, nil + } + unary(context.Background(), nil, nil, handler) + }) + + t.Run("with_error", func(t *testing.T) { + def := func(ctx context.Context) (Identity, error) { + return nil, errors.New("invalid request") + } + SetGlobalGRPCIdentityMapper(def) + // restore + defer SetGlobalGRPCIdentityMapper(nil) + _, err := unary(context.Background(), nil, nil, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, errors.New("some error") + }) + require.Error(t, err) + assert.Equal(t, "rpc error: code = PermissionDenied desc = unable to get identity: invalid request", err.Error()) + }) +} + func Test_RequestorIdentity(t *testing.T) { type roleName struct { Role string `json:"role,omitempty"` diff --git a/xhttp/identity/identity.go b/xhttp/identity/identity.go index 9947ad2..1360653 100644 --- a/xhttp/identity/identity.go +++ b/xhttp/identity/identity.go @@ -20,6 +20,9 @@ type Identity interface { // Mapper returns Identity from supplied HTTP request type Mapper func(*http.Request) (Identity, error) +// MapperFromContext returns Identity from supplied context +type MapperFromContext func(ctx context.Context) (Identity, error) + // NewIdentity returns a new Identity instance with the indicated role func NewIdentity(role, name, userID string) Identity { return identity{