From 33534ab00646cea898a027ebd18ab5ad03fd772f Mon Sep 17 00:00:00 2001 From: Fabi <38692350+fgerschwiler@users.noreply.github.com> Date: Mon, 15 Feb 2021 16:26:58 +0100 Subject: [PATCH] fix: usermemberships in authz (#1288) * fix: usermemberships in authz * fix: tests * fix: migration * fix: handler --- cmd/zitadel/startup.yaml | 1 + go.mod | 3 +- go.sum | 65 +++++ internal/api/authz/context.go | 21 ++ internal/api/authz/permissions.go | 46 +-- internal/api/authz/permissions_test.go | 112 +++++-- internal/api/authz/token.go | 7 +- internal/api/authz/token_test.go | 2 +- .../middleware/auth_interceptor_test.go | 3 +- .../eventsourcing/eventstore/user_grant.go | 31 +- .../eventsourcing/eventstore/user_grant.go | 119 +++++--- .../eventsourcing/handler/handler.go | 14 +- .../eventsourcing/handler/user_membership.go | 274 ++++++++++++++++++ .../repository/eventsourcing/repository.go | 6 +- .../eventsourcing/view/user_membership.go | 98 +++++++ .../cockroach/V1.29__user_memberships.sql | 18 ++ 16 files changed, 693 insertions(+), 127 deletions(-) create mode 100644 internal/authz/repository/eventsourcing/handler/user_membership.go create mode 100644 internal/authz/repository/eventsourcing/view/user_membership.go create mode 100644 migrations/cockroach/V1.29__user_memberships.sql diff --git a/cmd/zitadel/startup.yaml b/cmd/zitadel/startup.yaml index 8e92800397..4e0d66735f 100644 --- a/cmd/zitadel/startup.yaml +++ b/cmd/zitadel/startup.yaml @@ -17,6 +17,7 @@ Metrics: MeterName: 'github.com/caos/zitadel' AuthZ: + Domain: $ZITADEL_DEFAULT_DOMAIN Repository: Eventstore: ServiceName: 'AuthZ' diff --git a/go.mod b/go.mod index 3d92794490..1818ff6466 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0 github.com/cockroachdb/cockroach-go/v2 v2.1.0 github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 + github.com/envoyproxy/protoc-gen-validate v0.1.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/mock v1.4.4 @@ -71,7 +72,7 @@ require ( golang.org/x/tools v0.0.0-20201103235415-b653051172e4 google.golang.org/api v0.34.0 google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6 // indirect + google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6 google.golang.org/grpc v1.34.0 google.golang.org/protobuf v1.25.0 gopkg.in/square/go-jose.v2 v2.5.1 diff --git a/go.sum b/go.sum index a6583b85c6..23295c9dd8 100644 --- a/go.sum +++ b/go.sum @@ -127,13 +127,17 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/caos/logging v0.0.0-20191210002624-b3260f690a6a/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= github.com/caos/oidc v0.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ= +github.com/caos/oidc v0.13.2 h1:52oP3KB1UrZuwraBTLuwM9ItRIhJQMYOm1J5uQ0sYXw= github.com/caos/oidc v0.13.2/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY= github.com/caos/orbos v1.5.14-0.20210128140136-842933949472 h1:iti4tAKxBknjJkQcDKWaxlj9Jbng5kz5TpQzzyda49o= github.com/caos/orbos v1.5.14-0.20210128140136-842933949472/go.mod h1:ZLxNgPuYIlSvr80trezGGUIXng9gY2hHEdky/m0B/P0= @@ -145,7 +149,9 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -154,12 +160,14 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cloudflare-go v0.12.1/go.mod h1:gmzHQPAyHh8N8UgX0Z+3rSMRbNj47JDEbzXDICHVXys= github.com/cloudscale-ch/cloudscale-go-sdk v1.6.0/go.mod h1:FhOTOCgKAVvRRMQc1mC0D7xK/3zYnmcZBWFXNkacvMc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/cockroach-go/v2 v2.1.0 h1:zicZlBhWZu6wfK7Ezg4Owdc3HamLpRdBllPTT9tb+2k= github.com/cockroachdb/cockroach-go/v2 v2.1.0/go.mod h1:ilhrLnPDDwGHL+iK2UxQhp1UzUhst8sfItSAgCYwAyg= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -185,6 +193,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -194,6 +203,7 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 h1:eEEfwrmEwl0LVuWz/VkAefdgtPbX174Huu5dxxceihI= github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43/go.mod h1:/X2OJiJxjQ7alqWZqX9EtBTmZc+4qQ0LvZ1k5wP67RM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -211,20 +221,24 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -284,6 +298,7 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -293,6 +308,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -326,12 +342,14 @@ github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +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= @@ -362,6 +380,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= @@ -374,25 +393,32 @@ github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c2 github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y= github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -417,6 +443,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -425,6 +452,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM= github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -476,7 +504,9 @@ github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -501,11 +531,15 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23/go.mod h1:kBSna6b0/RzsOcOZf515vAXwSsXYusl2U7SA0XP09yI= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a h1:Z7+SSApKiwPjNic+NF9+j7h657Uyvdp/jA3iTKhpj4E= github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a/go.mod h1:/Pk5i/SqYdYv1cie5wGwoZ4P6TpgMi+Yf58mtJSHdOw= +github.com/kevinburke/go.uuid v1.2.0 h1:+1qP8NdkJfgOSTrrrUuA7h0djr1VY77HFXYjR+zUcUo= github.com/kevinburke/go.uuid v1.2.0/go.mod h1:9gVngk1Hq1FjwewVAjsWEUT+xc6jP+p62CASaGmQ0NQ= +github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 h1:KpuDJTaTPQAyWqETt70dHX3pMz65/XYTAZymrKKNvh8= github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8/go.mod h1:pD+iEcdAGVXld5foVN4e24zb/6fnb60tgZPZ3P/3T/I= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac h1:qQ7NAZEHpTyDfmZBH79KEiH3OK47Z+KvYVSR4sS3650= github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac/go.mod h1:Fm9alkN1/LPVY1eqD/psyMwPWE4VWl4P01/nTYZKzBk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -527,6 +561,7 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -566,11 +601,13 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -580,8 +617,10 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -601,6 +640,7 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU= github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -645,6 +685,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -653,12 +694,14 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -668,6 +711,7 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -676,6 +720,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= @@ -684,6 +729,7 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -692,6 +738,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= @@ -704,11 +751,13 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -744,7 +793,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= +github.com/ttacon/libphonenumber v1.1.0 h1:tC6kE4t8UI4OqQVQjW5q8gSWhG2wnY5moEpSEORdYm4= github.com/ttacon/libphonenumber v1.1.0/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -753,6 +804,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= @@ -780,13 +832,21 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/contrib v0.13.0 h1:q34CFu5REx9Dt2ksESHC/doIjFJkEg1oV3aSwlL5JR0= go.opentelemetry.io/contrib v0.13.0/go.mod h1:HzCu6ebm0ywgNxGaEfs3izyJOMP4rZnzxycyTgpI5Sg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0 h1:Ys1lnE8Y6rv3aKc9Ha13n7UM4pMHC0kvLSFtNx+gUfY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0/go.mod h1:ffigAFAlfY9AfFwJocEw88qbbvjAKfvqZg5tLyZv0l0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0 h1:dnZy1afzxEDrHybTYoJE1bQ3fphNwZF2ipSsynlITP4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0/go.mod h1:SeQm4RTCcZ2/hlMSTuHb7nwIROe5odBtgfKx+7MMqEs= +go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA= go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= +go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0 h1:Jf7AdsEoHKtNTWxXLj/g9XGjsGpdk0otEf0lx00r2Ps= go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0/go.mod h1:Tyh3ACxU9a1tu1mF4at7xvNu+BaiPThrr5XZmsoIW7g= +go.opentelemetry.io/otel/exporters/otlp v0.13.0 h1:iithmYmMAfLFgCW5TcRXHpXR5NTWO7nGtX3WcBiusVE= go.opentelemetry.io/otel/exporters/otlp v0.13.0/go.mod h1:YHH58UrGcqCKtBkY7sl3zPKpxBzfC1HUUYMRQONJJ9E= +go.opentelemetry.io/otel/exporters/stdout v0.13.0 h1:A+XiGIPQbGoJoBOJfKAKnZyiUSjSWvL3XWETUvtom5k= go.opentelemetry.io/otel/exporters/stdout v0.13.0/go.mod h1:JJt8RpNY6K+ft9ir3iKpceCvT/rhzJXEExGrWFCbv1o= +go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ= go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -854,6 +914,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -922,6 +983,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1054,12 +1116,14 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201030143252-cf7a54d06671/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201103235415-b653051172e4 h1:Qe0EMgvVYb6tmJhJHljCj3gS96hvSTkGNaIzp/ivq10= golang.org/x/tools v0.0.0-20201103235415-b653051172e4/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1176,6 +1240,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go index 374ef0c571..b7845aa82b 100644 --- a/internal/api/authz/context.go +++ b/internal/api/authz/context.go @@ -36,6 +36,27 @@ type Grant struct { Roles []string } +type Memberships []*Membership + +type Membership struct { + MemberType MemberType + AggregateID string + //ObjectID differs from aggregate id if obejct is sub of an aggregate + ObjectID string + + Roles []string +} + +type MemberType int32 + +const ( + MemberTypeUnspecified MemberType = iota + MemberTypeOrganisation + MemberTypeProject + MemberTypeProjectGrant + MemberTypeIam +) + func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ CtxData, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() diff --git a/internal/api/authz/permissions.go b/internal/api/authz/permissions.go index 6423f80fd7..c91eeaef55 100644 --- a/internal/api/authz/permissions.go +++ b/internal/api/authz/permissions.go @@ -2,7 +2,6 @@ package authz import ( "context" - "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/telemetry/tracing" ) @@ -16,41 +15,43 @@ func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPer } ctx = context.WithValue(ctx, dataKey, ctxData) - grant, err := t.ResolveGrant(ctx) + memberships, err := t.SearchMyMemberships(ctx) if err != nil { return nil, nil, err } - if grant == nil { + if len(memberships) == 0 { return requestedPermissions, nil, nil } - requestedPermissions, allPermissions = mapGrantToPermissions(requiredPerm, grant, authConfig) + requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, memberships, authConfig) return requestedPermissions, allPermissions, nil } -func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig Config) (requestPermissions, allPermissions []string) { +func mapMembershipsToPermissions(requiredPerm string, memberships []*Membership, authConfig Config) (requestPermissions, allPermissions []string) { requestPermissions = make([]string, 0) allPermissions = make([]string, 0) - for _, role := range grant.Roles { - requestPermissions, allPermissions = mapRoleToPerm(requiredPerm, role, authConfig, requestPermissions, allPermissions) + for _, membership := range memberships { + requestPermissions, allPermissions = mapMembershipToPerm(requiredPerm, membership, authConfig, requestPermissions, allPermissions) } return requestPermissions, allPermissions } -func mapRoleToPerm(requiredPerm, actualRole string, authConfig Config, requestPermissions, allPermissions []string) ([]string, []string) { - roleName, roleContextID := SplitPermission(actualRole) - perms := authConfig.getPermissionsFromRole(roleName) +func mapMembershipToPerm(requiredPerm string, membership *Membership, authConfig Config, requestPermissions, allPermissions []string) ([]string, []string) { + roleNames, roleContextID := roleWithContext(membership) + for _, roleName := range roleNames { + perms := authConfig.getPermissionsFromRole(roleName) - for _, p := range perms { - permWithCtx := addRoleContextIDToPerm(p, roleContextID) - if !ExistsPerm(allPermissions, permWithCtx) { - allPermissions = append(allPermissions, permWithCtx) - } + for _, p := range perms { + permWithCtx := addRoleContextIDToPerm(p, roleContextID) + if !ExistsPerm(allPermissions, permWithCtx) { + allPermissions = append(allPermissions, permWithCtx) + } - p, _ = SplitPermission(p) - if p == requiredPerm { - if !ExistsPerm(requestPermissions, permWithCtx) { - requestPermissions = append(requestPermissions, permWithCtx) + p, _ = SplitPermission(p) + if p == requiredPerm { + if !ExistsPerm(requestPermissions, permWithCtx) { + requestPermissions = append(requestPermissions, permWithCtx) + } } } } @@ -72,3 +73,10 @@ func ExistsPerm(existingPermissions []string, perm string) bool { } return false } + +func roleWithContext(membership *Membership) (roles []string, ctxID string) { + if membership.MemberType == MemberTypeProject || membership.MemberType == MemberTypeProjectGrant { + return membership.Roles, membership.ObjectID + } + return membership.Roles, "" +} diff --git a/internal/api/authz/permissions_test.go b/internal/api/authz/permissions_test.go index 69877fd4cb..77e65a7ae9 100644 --- a/internal/api/authz/permissions_test.go +++ b/internal/api/authz/permissions_test.go @@ -12,15 +12,14 @@ func getTestCtx(userID, orgID string) context.Context { } type testVerifier struct { - grant *Grant + memberships []*Membership } func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) { return "userID", "agentID", "de", nil } - -func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) { - return v.grant, nil +func (v *testVerifier) SearchMyMemberships(ctx context.Context) ([]*Membership, error) { + return v.memberships, nil } func (v *testVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { @@ -65,8 +64,10 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Empty Context", args: args{ ctxData: CtxData{}, - verifier: Start(&testVerifier{grant: &Grant{ - Roles: []string{"ORG_OWNER"}, + verifier: Start(&testVerifier{memberships: []*Membership{ + { + Roles: []string{"ORG_OWNER"}, + }, }}), requiredPerm: "project.read", authConfig: Config{ @@ -90,7 +91,7 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "No Grants", args: args{ ctxData: CtxData{}, - verifier: Start(&testVerifier{grant: &Grant{}}), + verifier: Start(&testVerifier{memberships: []*Membership{}}), requiredPerm: "project.read", authConfig: Config{ RolePermissionMappings: []RoleMapping{ @@ -111,8 +112,13 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Get Permissions", args: args{ ctxData: CtxData{UserID: "userID", OrgID: "orgID"}, - verifier: Start(&testVerifier{grant: &Grant{ - Roles: []string{"IAM_OWNER"}, + verifier: Start(&testVerifier{memberships: []*Membership{ + { + AggregateID: "IAM", + ObjectID: "IAM", + MemberType: MemberTypeIam, + Roles: []string{"IAM_OWNER"}, + }, }}), requiredPerm: "project.read", authConfig: Config{ @@ -150,10 +156,10 @@ func Test_GetUserMethodPermissions(t *testing.T) { } } -func Test_MapGrantsToPermissions(t *testing.T) { +func Test_MapMembershipToPermissions(t *testing.T) { type args struct { requiredPerm string - grant *Grant + membership []*Membership authConfig Config } tests := []struct { @@ -166,7 +172,14 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role existing perm", args: args{ requiredPerm: "project.read", - grant: &Grant{Roles: []string{"ORG_OWNER"}}, + membership: []*Membership{ + { + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -187,7 +200,14 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role not existing perm", args: args{ requiredPerm: "project.write", - grant: &Grant{Roles: []string{"ORG_OWNER"}}, + membership: []*Membership{ + { + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -208,7 +228,20 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles one existing", args: args{ requiredPerm: "project.read", - grant: &Grant{Roles: []string{"ORG_OWNER", "IAM_OWNER"}}, + membership: []*Membership{ + { + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, + { + AggregateID: "IAM", + ObjectID: "IAM", + MemberType: MemberTypeIam, + Roles: []string{"IAM_OWNER"}, + }, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -229,7 +262,20 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles, global and specific", args: args{ requiredPerm: "project.read", - grant: &Grant{Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}, + membership: []*Membership{ + { + AggregateID: "2", + ObjectID: "2", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, + { + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeProject, + Roles: []string{"PROJECT_OWNER"}, + }, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -249,7 +295,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - requestPerms, allPerms := mapGrantToPermissions(tt.args.requiredPerm, tt.args.grant, tt.args.authConfig) + requestPerms, allPerms := mapMembershipsToPermissions(tt.args.requiredPerm, tt.args.membership, tt.args.authConfig) if !equalStringArray(requestPerms, tt.requestPerms) { t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms) } @@ -260,10 +306,10 @@ func Test_MapGrantsToPermissions(t *testing.T) { } } -func Test_MapRoleToPerm(t *testing.T) { +func Test_MapMembershipToPerm(t *testing.T) { type args struct { requiredPerm string - actualRole string + membership *Membership authConfig Config requestPerms []string allPerms []string @@ -278,7 +324,12 @@ func Test_MapRoleToPerm(t *testing.T) { name: "first perm without context id", args: args{ requiredPerm: "project.read", - actualRole: "ORG_OWNER", + membership: &Membership{ + AggregateID: "Org", + ObjectID: "Org", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -301,7 +352,12 @@ func Test_MapRoleToPerm(t *testing.T) { name: "existing perm without context id", args: args{ requiredPerm: "project.read", - actualRole: "ORG_OWNER", + membership: &Membership{ + AggregateID: "Org", + ObjectID: "Org", + MemberType: MemberTypeOrganisation, + Roles: []string{"ORG_OWNER"}, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -324,7 +380,12 @@ func Test_MapRoleToPerm(t *testing.T) { name: "first perm with context id", args: args{ requiredPerm: "project.read", - actualRole: "PROJECT_OWNER:1", + membership: &Membership{ + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeProject, + Roles: []string{"PROJECT_OWNER"}, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -347,7 +408,12 @@ func Test_MapRoleToPerm(t *testing.T) { name: "perm with context id, existing global", args: args{ requiredPerm: "project.read", - actualRole: "PROJECT_OWNER:1", + membership: &Membership{ + AggregateID: "1", + ObjectID: "1", + MemberType: MemberTypeProject, + Roles: []string{"PROJECT_OWNER"}, + }, authConfig: Config{ RolePermissionMappings: []RoleMapping{ { @@ -369,7 +435,7 @@ func Test_MapRoleToPerm(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - requestPerms, allPerms := mapRoleToPerm(tt.args.requiredPerm, tt.args.actualRole, tt.args.authConfig, tt.args.requestPerms, tt.args.allPerms) + requestPerms, allPerms := mapMembershipToPerm(tt.args.requiredPerm, tt.args.membership, tt.args.authConfig, tt.args.requestPerms, tt.args.allPerms) if !equalStringArray(requestPerms, tt.requestPerms) { t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms) } diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go index 463b7396c2..834dd1b5e0 100644 --- a/internal/api/authz/token.go +++ b/internal/api/authz/token.go @@ -22,7 +22,7 @@ type TokenVerifier struct { type authZRepo interface { VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang string, err error) VerifierClientID(ctx context.Context, name string) (clientID string, err error) - ResolveGrants(ctx context.Context) (grant *Grant, err error) + SearchMyMemberships(ctx context.Context) ([]*Membership, error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) ExistsOrg(ctx context.Context, orgID string) error } @@ -86,11 +86,10 @@ func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) ( v.clients.Store(prefix, c) return c.id, nil } - -func (v *TokenVerifier) ResolveGrant(ctx context.Context) (_ *Grant, err error) { +func (v *TokenVerifier) SearchMyMemberships(ctx context.Context) (_ []*Membership, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - return v.authZRepo.ResolveGrants(ctx) + return v.authZRepo.SearchMyMemberships(ctx) } func (v *TokenVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (_ string, _ []string, err error) { diff --git a/internal/api/authz/token_test.go b/internal/api/authz/token_test.go index 2303e4ac69..ed928694b5 100644 --- a/internal/api/authz/token_test.go +++ b/internal/api/authz/token_test.go @@ -43,7 +43,7 @@ func Test_VerifyAccessToken(t *testing.T) { ctx: context.Background(), token: "Bearer AUTH", verifier: &TokenVerifier{ - authZRepo: &testVerifier{grant: &Grant{}}, + authZRepo: &testVerifier{memberships: []*Membership{}}, clients: func() sync.Map { m := sync.Map{} m.Store("service", &client{name: "name"}) diff --git a/internal/api/grpc/server/middleware/auth_interceptor_test.go b/internal/api/grpc/server/middleware/auth_interceptor_test.go index 570a4fbd94..14a7b96a98 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor_test.go +++ b/internal/api/grpc/server/middleware/auth_interceptor_test.go @@ -24,9 +24,10 @@ type verifierMock struct{} func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) { return "", "", "", nil } -func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) { +func (v *verifierMock) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) { return nil, nil } + func (v *verifierMock) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { return "", nil, nil } diff --git a/internal/auth/repository/eventsourcing/eventstore/user_grant.go b/internal/auth/repository/eventsourcing/eventstore/user_grant.go index cba39e4314..e1286dd7fb 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user_grant.go +++ b/internal/auth/repository/eventsourcing/eventstore/user_grant.go @@ -39,7 +39,7 @@ func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *gran result := &grant_model.UserGrantSearchResponse{ Offset: request.Offset, Limit: request.Limit, - TotalResult: uint64(count), + TotalResult: count, Result: model.UserGrantsToModel(grants), } if err == nil { @@ -258,7 +258,7 @@ func grantRespToOrgResp(grants *grant_model.UserGrantSearchResponse) *grant_mode func orgRespToOrgResp(orgs []*org_view_model.OrgView, count uint64) *grant_model.ProjectOrgSearchResponse { resp := &grant_model.ProjectOrgSearchResponse{ - TotalResult: uint64(count), + TotalResult: count, } resp.Result = make([]*grant_model.Org, len(orgs)) for i, o := range orgs { @@ -267,33 +267,6 @@ func orgRespToOrgResp(orgs []*org_view_model.OrgView, count uint64) *grant_model return resp } -func mergeOrgAndAdminGrant(ctxData authz.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *authz.Grant) { - if orgGrant != nil { - roles := orgGrant.RoleKeys - if iamAdminGrant != nil { - roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) - } - grant = &authz.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} - } else if iamAdminGrant != nil { - grant = &authz.Grant{ - OrgID: ctxData.OrgID, - Roles: iamAdminGrant.RoleKeys, - } - } - return grant -} - -func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { - result := make([]string, 0) - result = append(result, iamAdminRoles...) - for _, role := range orgRoles { - if !authz.ExistsPerm(result, role) { - result = append(result, role) - } - } - return result -} - func containsOrg(orgs []*grant_model.Org, resourceOwner string) bool { for _, org := range orgs { if org.OrgID == resourceOwner { diff --git a/internal/authz/repository/eventsourcing/eventstore/user_grant.go b/internal/authz/repository/eventsourcing/eventstore/user_grant.go index 0d217fa9ad..b9b76c6353 100644 --- a/internal/authz/repository/eventsourcing/eventstore/user_grant.go +++ b/internal/authz/repository/eventsourcing/eventstore/user_grant.go @@ -2,6 +2,9 @@ package eventstore import ( "context" + global_model "github.com/caos/zitadel/internal/model" + user_model "github.com/caos/zitadel/internal/user/model" + user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" @@ -9,7 +12,6 @@ import ( iam_model "github.com/caos/zitadel/internal/iam/model" iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" grant_model "github.com/caos/zitadel/internal/usergrant/model" - "github.com/caos/zitadel/internal/usergrant/repository/view/model" ) type UserGrantRepo struct { @@ -24,46 +26,70 @@ func (repo *UserGrantRepo) Health() error { return repo.View.Health() } -func (repo *UserGrantRepo) ResolveGrants(ctx context.Context) (*authz.Grant, error) { - err := repo.FillIamProjectID(ctx) +func (repo *UserGrantRepo) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) { + memberships, err := repo.searchUserMemberships(ctx) if err != nil { return nil, err } - ctxData := authz.GetCtxData(ctx) - - orgGrant, err := repo.View.UserGrantByIDs(ctxData.OrgID, repo.IamProjectID, ctxData.UserID) - if err != nil && !caos_errs.IsNotFound(err) { - return nil, err - } - iamAdminGrant, err := repo.View.UserGrantByIDs(repo.IamID, repo.IamProjectID, ctxData.UserID) - if err != nil && !caos_errs.IsNotFound(err) { - return nil, err - } - - return mergeOrgAndAdminGrant(ctxData, orgGrant, iamAdminGrant), nil + return userMembershipsToMemberships(memberships), nil } func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) { - grant, err := repo.ResolveGrants(ctx) + memberships, err := repo.searchUserMemberships(ctx) if err != nil { return nil, err } - - if grant == nil { - return []string{}, nil - } permissions := &grant_model.Permissions{Permissions: []string{}} - for _, role := range grant.Roles { - roleName, ctxID := authz.SplitPermission(role) - for _, mapping := range repo.Auth.RolePermissionMappings { - if mapping.Role == roleName { - permissions.AppendPermissions(ctxID, mapping.Permissions...) - } + for _, membership := range memberships { + for _, role := range membership.Roles { + permissions = repo.mapRoleToPermission(permissions, membership, role) } } return permissions.Permissions, nil } +func (repo *UserGrantRepo) searchUserMemberships(ctx context.Context) ([]*user_view_model.UserMembershipView, error) { + ctxData := authz.GetCtxData(ctx) + orgMemberships, orgCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{ + Queries: []*user_model.UserMembershipSearchQuery{ + { + Key: user_model.UserMembershipSearchKeyUserID, + Method: global_model.SearchMethodEquals, + Value: ctxData.UserID, + }, + { + Key: user_model.UserMembershipSearchKeyResourceOwner, + Method: global_model.SearchMethodEquals, + Value: ctxData.OrgID, + }, + }, + }) + if err != nil { + return nil, err + } + iamMemberships, iamCount, err := repo.View.SearchUserMemberships(&user_model.UserMembershipSearchRequest{ + Queries: []*user_model.UserMembershipSearchQuery{ + { + Key: user_model.UserMembershipSearchKeyUserID, + Method: global_model.SearchMethodEquals, + Value: ctxData.UserID, + }, + { + Key: user_model.UserMembershipSearchKeyAggregateID, + Method: global_model.SearchMethodEquals, + Value: repo.IamID, + }, + }, + }) + if err != nil { + return nil, err + } + if orgCount == 0 && iamCount == 0 { + return []*user_view_model.UserMembershipView{}, nil + } + return append(orgMemberships, iamMemberships...), nil +} + func (repo *UserGrantRepo) FillIamProjectID(ctx context.Context) error { if repo.IamProjectID != "" { return nil @@ -79,29 +105,32 @@ func (repo *UserGrantRepo) FillIamProjectID(ctx context.Context) error { return nil } -func mergeOrgAndAdminGrant(ctxData authz.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *authz.Grant) { - if orgGrant != nil { - roles := orgGrant.RoleKeys - if iamAdminGrant != nil { - roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) - } - grant = &authz.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} - } else if iamAdminGrant != nil { - grant = &authz.Grant{ - OrgID: ctxData.OrgID, - Roles: iamAdminGrant.RoleKeys, +func (repo *UserGrantRepo) mapRoleToPermission(permissions *grant_model.Permissions, membership *user_view_model.UserMembershipView, role string) *grant_model.Permissions { + for _, mapping := range repo.Auth.RolePermissionMappings { + if mapping.Role == role { + ctxID := "" + if membership.MemberType == int32(user_model.MemberTypeProject) || membership.MemberType == int32(user_model.MemberTypeProjectGrant) { + ctxID = membership.ObjectID + } + permissions.AppendPermissions(ctxID, mapping.Permissions...) } } - return grant + return permissions } -func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { - result := make([]string, 0) - result = append(result, iamAdminRoles...) - for _, role := range orgRoles { - if !authz.ExistsPerm(result, role) { - result = append(result, role) - } +func userMembershipToMembership(membership *user_view_model.UserMembershipView) *authz.Membership { + return &authz.Membership{ + MemberType: authz.MemberType(membership.MemberType), + AggregateID: membership.AggregateID, + ObjectID: membership.ObjectID, + Roles: membership.Roles, + } +} + +func userMembershipsToMemberships(memberships []*user_view_model.UserMembershipView) []*authz.Membership { + result := make([]*authz.Membership, len(memberships)) + for i, m := range memberships { + result[i] = userMembershipToMembership(m) } return result } diff --git a/internal/authz/repository/eventsourcing/handler/handler.go b/internal/authz/repository/eventsourcing/handler/handler.go index ee21d1b020..b18098de16 100644 --- a/internal/authz/repository/eventsourcing/handler/handler.go +++ b/internal/authz/repository/eventsourcing/handler/handler.go @@ -1,6 +1,7 @@ package handler import ( + "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "time" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" @@ -8,7 +9,8 @@ import ( "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" - iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" + project_events "github.com/caos/zitadel/internal/project/repository/eventsourcing" ) type Configs map[string]*Config @@ -31,15 +33,21 @@ func (h *handler) Eventstore() eventstore.Eventstore { } type EventstoreRepos struct { - IAMEvents *iam_events.IAMEventstore + IAMEvents *eventsourcing.IAMEventstore + OrgEvents *org_events.OrgEventstore + ProjectEvents *project_events.ProjectEventstore } func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler { return []query.Handler{ newUserGrant( - handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es}, + handler{view, bulkLimit, configs.cycleDuration("UserGrants"), errorCount, es}, repos.IAMEvents, systemDefaults.IamID), + newUserMembership( + handler{view, bulkLimit, configs.cycleDuration("UserMemberships"), errorCount, es}, + repos.OrgEvents, + repos.ProjectEvents), newApplication( handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}), newOrg( diff --git a/internal/authz/repository/eventsourcing/handler/user_membership.go b/internal/authz/repository/eventsourcing/handler/user_membership.go new file mode 100644 index 0000000000..4e1b5a81cf --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/user_membership.go @@ -0,0 +1,274 @@ +package handler + +import ( + "context" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/query" + "github.com/caos/zitadel/internal/eventstore/spooler" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model" +) + +const ( + userMembershipTable = "authz.user_memberships" +) + +type UserMembership struct { + handler + orgEvents *org_event.OrgEventstore + projectEvents *proj_event.ProjectEventstore + subscription *eventstore.Subscription +} + +func newUserMembership( + handler handler, + orgEvents *org_event.OrgEventstore, + projectEvents *proj_event.ProjectEventstore, +) *UserMembership { + h := &UserMembership{ + handler: handler, + orgEvents: orgEvents, + projectEvents: projectEvents, + } + + h.subscribe() + + return h +} + +func (m *UserMembership) subscribe() { + m.subscription = m.es.Subscribe(m.AggregateTypes()...) + go func() { + for event := range m.subscription.Events { + query.ReduceEvent(m, event) + } + }() +} + +func (m *UserMembership) ViewModel() string { + return userMembershipTable +} + +func (_ *UserMembership) AggregateTypes() []es_models.AggregateType { + return []es_models.AggregateType{iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate, model.UserAggregate} +} + +func (m *UserMembership) CurrentSequence() (uint64, error) { + sequence, err := m.view.GetLatestUserMembershipSequence() + if err != nil { + return 0, err + } + return sequence.CurrentSequence, nil +} + +func (m *UserMembership) EventQuery() (*models.SearchQuery, error) { + sequence, err := m.view.GetLatestUserMembershipSequence() + if err != nil { + return nil, err + } + return es_models.NewSearchQuery(). + AggregateTypeFilter(m.AggregateTypes()...). + LatestSequenceFilter(sequence.CurrentSequence), nil +} + +func (m *UserMembership) Reduce(event *models.Event) (err error) { + switch event.AggregateType { + case iam_es_model.IAMAggregate: + err = m.processIAM(event) + case org_es_model.OrgAggregate: + err = m.processOrg(event) + case proj_es_model.ProjectAggregate: + err = m.processProject(event) + case model.UserAggregate: + err = m.processUser(event) + } + return err +} + +func (m *UserMembership) processIAM(event *models.Event) (err error) { + member := new(usr_es_model.UserMembershipView) + err = member.AppendEvent(event) + if err != nil { + return err + } + switch event.Type { + case iam_es_model.IAMMemberAdded: + m.fillIamDisplayName(member) + case iam_es_model.IAMMemberChanged: + member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam) + if err != nil { + return err + } + err = member.AppendEvent(event) + case iam_es_model.IAMMemberRemoved: + return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event) + default: + return m.view.ProcessedUserMembershipSequence(event) + } + if err != nil { + return err + } + return m.view.PutUserMembership(member, event) +} + +func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) { + member.DisplayName = member.AggregateID + member.ResourceOwnerName = member.ResourceOwner +} + +func (m *UserMembership) processOrg(event *models.Event) (err error) { + member := new(usr_es_model.UserMembershipView) + err = member.AppendEvent(event) + if err != nil { + return err + } + switch event.Type { + case org_es_model.OrgMemberAdded: + err = m.fillOrgName(member) + case org_es_model.OrgMemberChanged: + member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation) + if err != nil { + return err + } + err = member.AppendEvent(event) + case org_es_model.OrgMemberRemoved: + return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event) + case org_es_model.OrgChanged: + return m.updateOrgName(event) + default: + return m.view.ProcessedUserMembershipSequence(event) + } + if err != nil { + return err + } + return m.view.PutUserMembership(member, event) +} + +func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) { + org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(member.ResourceOwner)) + if err != nil { + return err + } + member.ResourceOwnerName = org.Name + if member.AggregateID == org.AggregateID { + member.DisplayName = org.Name + } + return nil +} + +func (m *UserMembership) updateOrgName(event *models.Event) error { + org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID)) + if err != nil { + return err + } + + memberships, err := m.view.UserMembershipsByResourceOwner(event.ResourceOwner) + if err != nil { + return err + } + for _, membership := range memberships { + membership.ResourceOwnerName = org.Name + if membership.AggregateID == event.AggregateID { + membership.DisplayName = org.Name + } + } + return m.view.BulkPutUserMemberships(memberships, event) +} + +func (m *UserMembership) processProject(event *models.Event) (err error) { + member := new(usr_es_model.UserMembershipView) + err = member.AppendEvent(event) + if err != nil { + return err + } + switch event.Type { + case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded: + err = m.fillProjectDisplayName(member) + if err != nil { + return err + } + err = m.fillOrgName(member) + case proj_es_model.ProjectMemberChanged: + member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject) + if err != nil { + return err + } + err = member.AppendEvent(event) + case proj_es_model.ProjectMemberRemoved: + return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event) + case proj_es_model.ProjectGrantMemberChanged: + member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant) + if err != nil { + return err + } + err = member.AppendEvent(event) + case proj_es_model.ProjectGrantMemberRemoved: + return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event) + case proj_es_model.ProjectChanged: + return m.updateProjectDisplayName(event) + case proj_es_model.ProjectRemoved: + return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event) + case proj_es_model.ProjectGrantRemoved: + return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event) + default: + return m.view.ProcessedUserMembershipSequence(event) + } + if err != nil { + return err + } + return m.view.PutUserMembership(member, event) +} + +func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) { + project, err := m.projectEvents.ProjectByID(context.Background(), member.AggregateID) + if err != nil { + return err + } + member.DisplayName = project.Name + return nil +} + +func (m *UserMembership) updateProjectDisplayName(event *models.Event) error { + project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID) + if err != nil { + return err + } + + memberships, err := m.view.UserMembershipsByAggregateID(event.AggregateID) + if err != nil { + return err + } + for _, membership := range memberships { + membership.DisplayName = project.Name + } + return m.view.BulkPutUserMemberships(memberships, event) +} + +func (m *UserMembership) processUser(event *models.Event) (err error) { + switch event.Type { + case model.UserRemoved: + return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event) + default: + return m.view.ProcessedUserMembershipSequence(event) + } +} + +func (m *UserMembership) OnError(event *models.Event, err error) error { + logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler") + return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip) +} + +func (m *UserMembership) OnSuccess() error { + return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp) +} diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go index e42a152cdb..ee5d630e6d 100644 --- a/internal/authz/repository/eventsourcing/repository.go +++ b/internal/authz/repository/eventsourcing/repository.go @@ -2,6 +2,7 @@ package eventsourcing import ( "context" + es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" @@ -22,6 +23,7 @@ import ( ) type Config struct { + Domain string Eventstore es_int.Config AuthRequest cache.Config View types.SQL @@ -60,6 +62,8 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults) (* if err != nil { return nil, err } + org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) + project, err := es_proj.StartProject(es_proj.ProjectConfig{ Eventstore: es, Cache: conf.Eventstore.Cache, @@ -77,7 +81,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults) (* if err != nil { return nil, err } - repos := handler.EventstoreRepos{IAMEvents: iam} + repos := handler.EventstoreRepos{IAMEvents: iam, OrgEvents: org, ProjectEvents: project} spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) return &EsRepository{ diff --git a/internal/authz/repository/eventsourcing/view/user_membership.go b/internal/authz/repository/eventsourcing/view/user_membership.go new file mode 100644 index 0000000000..add7b3aa81 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/user_membership.go @@ -0,0 +1,98 @@ +package view + +import ( + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/user/repository/view" + "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/view/repository" +) + +const ( + userMembershipTable = "authz.user_memberships" +) + +func (v *View) UserMembershipByIDs(userID, aggregateID, objectID string, memberType usr_model.MemberType) (*model.UserMembershipView, error) { + return view.UserMembershipByIDs(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType) +} + +func (v *View) UserMembershipsByAggregateID(aggregateID string) ([]*model.UserMembershipView, error) { + return view.UserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID) +} + +func (v *View) UserMembershipsByResourceOwner(resourceOwner string) ([]*model.UserMembershipView, error) { + return view.UserMembershipsByResourceOwner(v.Db, userMembershipTable, resourceOwner) +} + +func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequest) ([]*model.UserMembershipView, uint64, error) { + return view.SearchUserMemberships(v.Db, userMembershipTable, request) +} + +func (v *View) PutUserMembership(membership *model.UserMembershipView, event *models.Event) error { + err := view.PutUserMembership(v.Db, userMembershipTable, membership) + if err != nil { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, event *models.Event) error { + err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...) + if err != nil { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, event *models.Event) error { + err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) DeleteUserMembershipsByUserID(userID string, event *models.Event) error { + err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, event *models.Event) error { + err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, event *models.Event) error { + err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserMembershipSequence(event) +} + +func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) { + return v.latestSequence(userMembershipTable) +} + +func (v *View) ProcessedUserMembershipSequence(event *models.Event) error { + return v.saveCurrentSequence(userMembershipTable, event) +} + +func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error { + return v.updateSpoolerRunSequence(userMembershipTable) +} + +func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64) (*repository.FailedEvent, error) { + return v.latestFailedEvent(userMembershipTable, sequence) +} + +func (v *View) ProcessedUserMembershipFailedEvent(failedEvent *repository.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/migrations/cockroach/V1.29__user_memberships.sql b/migrations/cockroach/V1.29__user_memberships.sql new file mode 100644 index 0000000000..30d4259ce9 --- /dev/null +++ b/migrations/cockroach/V1.29__user_memberships.sql @@ -0,0 +1,18 @@ +CREATE TABLE authz.user_memberships ( + user_id TEXT, + member_type SMALLINT, + aggregate_id TEXT, + object_id TEXT, + + roles TEXT ARRAY, + display_name TEXT, + resource_owner TEXT, + resource_owner_name TEXT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + PRIMARY KEY (user_id, member_type, aggregate_id, object_id) +); + +ALTER TABLE authz.user_memberships OWNER TO admin; \ No newline at end of file