mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:47:22 +00:00
feat: project roles (#843)
* fix logging * token verification * feat: assert roles * feat: add project role assertion on project and token type on app * id and access token role assertion * add project role check * user grant required step in login * update library * fix merge * fix merge * fix merge * update oidc library * fix tests * add tests for GrantRequiredStep * add missing field ProjectRoleCheck on project view model * fix project create * fix project create
This commit is contained in:
parent
f5a7a0a09f
commit
a321d850ae
3
go.mod
3
go.mod
@ -15,7 +15,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go v1.34.24 // indirect
|
github.com/aws/aws-sdk-go v1.34.24 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
|
||||||
github.com/caos/logging v0.0.2
|
github.com/caos/logging v0.0.2
|
||||||
github.com/caos/oidc v0.11.1
|
github.com/caos/oidc v0.12.0
|
||||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.0.7
|
github.com/cockroachdb/cockroach-go/v2 v2.0.7
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.4.1
|
github.com/envoyproxy/protoc-gen-validate v0.4.1
|
||||||
@ -37,7 +37,6 @@ require (
|
|||||||
github.com/kevinburke/go.uuid v1.2.0 // indirect
|
github.com/kevinburke/go.uuid v1.2.0 // indirect
|
||||||
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 // indirect
|
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 // indirect
|
||||||
github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac
|
github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
|
||||||
github.com/lib/pq v1.8.0
|
github.com/lib/pq v1.8.0
|
||||||
github.com/mattn/go-colorable v0.1.7 // indirect
|
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||||
|
19
go.sum
19
go.sum
@ -71,12 +71,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
|
|||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
|
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/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
|
||||||
github.com/caos/oidc v0.10.0 h1:/GKyQgKHvkc2jNCXzmdJs9hCXDYdArCMm3d5FXaiNWA=
|
github.com/caos/oidc v0.12.0 h1:BcEwgeq8fpum2hdc47ZDOTwnc4KdHpos1NRbE1JcHN8=
|
||||||
github.com/caos/oidc v0.10.0/go.mod h1:RREtWSRzH/mXQXJkxB63mFDZ/RUNyzoU6czd6UJfvJI=
|
github.com/caos/oidc v0.12.0/go.mod h1:R9UKITZmSo5vNhSLUYcTDH8pAaV2xwPASXg8wpEs2xQ=
|
||||||
github.com/caos/oidc v0.11.0 h1:larwR0ur4hcHXkMtlXbHApv4DUr5yu/zbxBeGjcpTXk=
|
|
||||||
github.com/caos/oidc v0.11.0/go.mod h1:R9UKITZmSo5vNhSLUYcTDH8pAaV2xwPASXg8wpEs2xQ=
|
|
||||||
github.com/caos/oidc v0.11.1 h1:7Nkup+fiU/zZVN61BfGOTzuloD7aOdqA3V9eNrJv5xc=
|
|
||||||
github.com/caos/oidc v0.11.1/go.mod h1:R9UKITZmSo5vNhSLUYcTDH8pAaV2xwPASXg8wpEs2xQ=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
@ -280,8 +276,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
@ -349,8 +343,6 @@ github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea/go.mod h1:DKyhr
|
|||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
|
||||||
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 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
|
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
|
||||||
@ -409,8 +401,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnk
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
|
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -484,8 +474,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up
|
|||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
|
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -546,9 +534,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zr
|
|||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201013081832-0aaa2718063a h1:bhXnJ7fn2SiL+C8iOWPfNBJKDTjUByftpPW7b9CX94U=
|
|
||||||
golang.org/x/sys v0.0.0-20201013081832-0aaa2718063a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -52,8 +52,11 @@ func (m *IamMember) processIamMember(event *models.Event) (err error) {
|
|||||||
member := new(iam_model.IAMMemberView)
|
member := new(iam_model.IAMMemberView)
|
||||||
switch event.Type {
|
switch event.Type {
|
||||||
case model.IAMMemberAdded:
|
case model.IAMMemberAdded:
|
||||||
member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
m.fillData(member)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = m.fillData(member)
|
||||||
case model.IAMMemberChanged:
|
case model.IAMMemberChanged:
|
||||||
err := member.SetData(event)
|
err := member.SetData(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -63,7 +66,7 @@ func (m *IamMember) processIamMember(event *models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
case model.IAMMemberRemoved:
|
case model.IAMMemberRemoved:
|
||||||
err := member.SetData(event)
|
err := member.SetData(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,7 +35,10 @@ func (o *Org) Reduce(event *es_models.Event) error {
|
|||||||
|
|
||||||
switch event.Type {
|
switch event.Type {
|
||||||
case model.OrgAdded:
|
case model.OrgAdded:
|
||||||
org.AppendEvent(event)
|
err := org.AppendEvent(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case model.OrgChanged:
|
case model.OrgChanged:
|
||||||
err := org.SetData(event)
|
err := org.SetData(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,34 +44,40 @@ func appConfigFromModel(app *proj_model.Application) management.AppConfig {
|
|||||||
|
|
||||||
func oidcConfigFromModel(config *proj_model.OIDCConfig) *management.OIDCConfig {
|
func oidcConfigFromModel(config *proj_model.OIDCConfig) *management.OIDCConfig {
|
||||||
return &management.OIDCConfig{
|
return &management.OIDCConfig{
|
||||||
RedirectUris: config.RedirectUris,
|
RedirectUris: config.RedirectUris,
|
||||||
ResponseTypes: oidcResponseTypesFromModel(config.ResponseTypes),
|
ResponseTypes: oidcResponseTypesFromModel(config.ResponseTypes),
|
||||||
GrantTypes: oidcGrantTypesFromModel(config.GrantTypes),
|
GrantTypes: oidcGrantTypesFromModel(config.GrantTypes),
|
||||||
ApplicationType: oidcApplicationTypeFromModel(config.ApplicationType),
|
ApplicationType: oidcApplicationTypeFromModel(config.ApplicationType),
|
||||||
ClientId: config.ClientID,
|
ClientId: config.ClientID,
|
||||||
ClientSecret: config.ClientSecretString,
|
ClientSecret: config.ClientSecretString,
|
||||||
AuthMethodType: oidcAuthMethodTypeFromModel(config.AuthMethodType),
|
AuthMethodType: oidcAuthMethodTypeFromModel(config.AuthMethodType),
|
||||||
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
||||||
Version: oidcVersionFromModel(config.OIDCVersion),
|
Version: oidcVersionFromModel(config.OIDCVersion),
|
||||||
NoneCompliant: config.Compliance.NoneCompliant,
|
NoneCompliant: config.Compliance.NoneCompliant,
|
||||||
ComplianceProblems: complianceProblemsToLocalizedMessages(config.Compliance.Problems),
|
ComplianceProblems: complianceProblemsToLocalizedMessages(config.Compliance.Problems),
|
||||||
DevMode: config.DevMode,
|
DevMode: config.DevMode,
|
||||||
|
AccessTokenType: oidcTokenTypeFromModel(config.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: config.AccessTokenRoleAssertion,
|
||||||
|
IdTokenRoleAssertion: config.IDTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *management.OIDCConfig {
|
func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *management.OIDCConfig {
|
||||||
return &management.OIDCConfig{
|
return &management.OIDCConfig{
|
||||||
RedirectUris: app.OIDCRedirectUris,
|
RedirectUris: app.OIDCRedirectUris,
|
||||||
ResponseTypes: oidcResponseTypesFromModel(app.OIDCResponseTypes),
|
ResponseTypes: oidcResponseTypesFromModel(app.OIDCResponseTypes),
|
||||||
GrantTypes: oidcGrantTypesFromModel(app.OIDCGrantTypes),
|
GrantTypes: oidcGrantTypesFromModel(app.OIDCGrantTypes),
|
||||||
ApplicationType: oidcApplicationTypeFromModel(app.OIDCApplicationType),
|
ApplicationType: oidcApplicationTypeFromModel(app.OIDCApplicationType),
|
||||||
ClientId: app.OIDCClientID,
|
ClientId: app.OIDCClientID,
|
||||||
AuthMethodType: oidcAuthMethodTypeFromModel(app.OIDCAuthMethodType),
|
AuthMethodType: oidcAuthMethodTypeFromModel(app.OIDCAuthMethodType),
|
||||||
PostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris,
|
PostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris,
|
||||||
Version: oidcVersionFromModel(app.OIDCVersion),
|
Version: oidcVersionFromModel(app.OIDCVersion),
|
||||||
NoneCompliant: app.NoneCompliant,
|
NoneCompliant: app.NoneCompliant,
|
||||||
ComplianceProblems: complianceProblemsToLocalizedMessages(app.ComplianceProblems),
|
ComplianceProblems: complianceProblemsToLocalizedMessages(app.ComplianceProblems),
|
||||||
DevMode: app.DevMode,
|
DevMode: app.DevMode,
|
||||||
|
AccessTokenType: oidcTokenTypeFromModel(app.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
|
||||||
|
IdTokenRoleAssertion: app.IDTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +98,17 @@ func oidcAppCreateToModel(app *management.OIDCApplicationCreate) *proj_model.App
|
|||||||
Name: app.Name,
|
Name: app.Name,
|
||||||
Type: proj_model.AppTypeOIDC,
|
Type: proj_model.AppTypeOIDC,
|
||||||
OIDCConfig: &proj_model.OIDCConfig{
|
OIDCConfig: &proj_model.OIDCConfig{
|
||||||
OIDCVersion: oidcVersionToModel(app.Version),
|
OIDCVersion: oidcVersionToModel(app.Version),
|
||||||
RedirectUris: app.RedirectUris,
|
RedirectUris: app.RedirectUris,
|
||||||
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
|
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
|
||||||
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
|
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
|
||||||
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
|
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
|
||||||
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
|
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
|
||||||
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
|
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
|
||||||
DevMode: app.DevMode,
|
DevMode: app.DevMode,
|
||||||
|
AccessTokenType: oidcTokenTypeToModel(app.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
|
||||||
|
IDTokenRoleAssertion: app.IdTokenRoleAssertion,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,14 +128,17 @@ func oidcConfigUpdateToModel(app *management.OIDCConfigUpdate) *proj_model.OIDCC
|
|||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: app.ProjectId,
|
AggregateID: app.ProjectId,
|
||||||
},
|
},
|
||||||
AppID: app.ApplicationId,
|
AppID: app.ApplicationId,
|
||||||
RedirectUris: app.RedirectUris,
|
RedirectUris: app.RedirectUris,
|
||||||
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
|
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
|
||||||
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
|
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
|
||||||
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
|
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
|
||||||
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
|
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
|
||||||
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
|
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
|
||||||
DevMode: app.DevMode,
|
DevMode: app.DevMode,
|
||||||
|
AccessTokenType: oidcTokenTypeToModel(app.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
|
||||||
|
IDTokenRoleAssertion: app.IdTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +363,28 @@ func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) managem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func oidcTokenTypeToModel(tokenType management.OIDCTokenType) proj_model.OIDCTokenType {
|
||||||
|
switch tokenType {
|
||||||
|
case management.OIDCTokenType_OIDCTokenType_Bearer:
|
||||||
|
return proj_model.OIDCTokenTypeBearer
|
||||||
|
case management.OIDCTokenType_OIDCTokenType_JWT:
|
||||||
|
return proj_model.OIDCTokenTypeJWT
|
||||||
|
default:
|
||||||
|
return proj_model.OIDCTokenTypeBearer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func oidcTokenTypeFromModel(tokenType proj_model.OIDCTokenType) management.OIDCTokenType {
|
||||||
|
switch tokenType {
|
||||||
|
case proj_model.OIDCTokenTypeBearer:
|
||||||
|
return management.OIDCTokenType_OIDCTokenType_Bearer
|
||||||
|
case proj_model.OIDCTokenTypeJWT:
|
||||||
|
return management.OIDCTokenType_OIDCTokenType_JWT
|
||||||
|
default:
|
||||||
|
return management.OIDCTokenType_OIDCTokenType_Bearer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func oidcVersionFromModel(version proj_model.OIDCVersion) management.OIDCVersion {
|
func oidcVersionFromModel(version proj_model.OIDCVersion) management.OIDCVersion {
|
||||||
switch version {
|
switch version {
|
||||||
case proj_model.OIDCVersionV1:
|
case proj_model.OIDCVersionV1:
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) CreateProject(ctx context.Context, in *management.ProjectCreateRequest) (*management.Project, error) {
|
func (s *Server) CreateProject(ctx context.Context, in *management.ProjectCreateRequest) (*management.Project, error) {
|
||||||
project, err := s.project.CreateProject(ctx, in.Name)
|
project, err := s.project.CreateProject(ctx, projectCreateToModel(in))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,14 @@ func projectFromModel(project *proj_model.Project) *management.Project {
|
|||||||
logging.Log("GRPC-di7rw").OnError(err).Debug("unable to parse timestamp")
|
logging.Log("GRPC-di7rw").OnError(err).Debug("unable to parse timestamp")
|
||||||
|
|
||||||
return &management.Project{
|
return &management.Project{
|
||||||
Id: project.AggregateID,
|
Id: project.AggregateID,
|
||||||
State: projectStateFromModel(project.State),
|
State: projectStateFromModel(project.State),
|
||||||
CreationDate: creationDate,
|
CreationDate: creationDate,
|
||||||
ChangeDate: changeDate,
|
ChangeDate: changeDate,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
Sequence: project.Sequence,
|
Sequence: project.Sequence,
|
||||||
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +62,15 @@ func projectViewFromModel(project *proj_model.ProjectView) *management.ProjectVi
|
|||||||
logging.Log("GRPC-sope3").OnError(err).Debug("unable to parse timestamp")
|
logging.Log("GRPC-sope3").OnError(err).Debug("unable to parse timestamp")
|
||||||
|
|
||||||
return &management.ProjectView{
|
return &management.ProjectView{
|
||||||
ProjectId: project.ProjectID,
|
ProjectId: project.ProjectID,
|
||||||
State: projectStateFromModel(project.State),
|
State: projectStateFromModel(project.State),
|
||||||
CreationDate: creationDate,
|
CreationDate: creationDate,
|
||||||
ChangeDate: changeDate,
|
ChangeDate: changeDate,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
Sequence: project.Sequence,
|
Sequence: project.Sequence,
|
||||||
ResourceOwner: project.ResourceOwner,
|
ResourceOwner: project.ResourceOwner,
|
||||||
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,12 +121,22 @@ func projectStateFromModel(state proj_model.ProjectState) management.ProjectStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func projectCreateToModel(project *management.ProjectCreateRequest) *proj_model.Project {
|
||||||
|
return &proj_model.Project{
|
||||||
|
Name: project.Name,
|
||||||
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func projectUpdateToModel(project *management.ProjectUpdateRequest) *proj_model.Project {
|
func projectUpdateToModel(project *management.ProjectUpdateRequest) *proj_model.Project {
|
||||||
return &proj_model.Project{
|
return &proj_model.Project{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: project.Id,
|
AggregateID: project.Id,
|
||||||
},
|
},
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ func userGrantViewFromModel(grant *grant_model.UserGrantView) *management.UserGr
|
|||||||
Email: grant.Email,
|
Email: grant.Email,
|
||||||
ProjectName: grant.ProjectName,
|
ProjectName: grant.ProjectName,
|
||||||
OrgName: grant.OrgName,
|
OrgName: grant.OrgName,
|
||||||
OrgDomain: grant.OrgDomain,
|
OrgDomain: grant.OrgPrimaryDomain,
|
||||||
RoleKeys: grant.RoleKeys,
|
RoleKeys: grant.RoleKeys,
|
||||||
UserId: grant.UserID,
|
UserId: grant.UserID,
|
||||||
ProjectId: grant.ProjectID,
|
ProjectId: grant.ProjectID,
|
||||||
|
@ -3,6 +3,7 @@ package oidc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/http/middleware"
|
"github.com/caos/zitadel/internal/api/http/middleware"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,6 +21,14 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
|
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
|
||||||
}
|
}
|
||||||
|
app, err := o.repo.ApplicationByClientID(ctx, req.ClientID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal")
|
||||||
|
}
|
||||||
|
req.Scopes, err = o.assertProjectRoleScopes(app, req.Scopes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-Gqrfg", "Errors.Internal")
|
||||||
|
}
|
||||||
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
|
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
|
||||||
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
|
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -102,3 +112,22 @@ func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error)
|
|||||||
func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error {
|
func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error {
|
||||||
return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm)
|
return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OPStorage) assertProjectRoleScopes(app *proj_model.ApplicationView, scopes []string) ([]string, error) {
|
||||||
|
if !app.ProjectRoleAssertion {
|
||||||
|
return scopes, nil
|
||||||
|
}
|
||||||
|
for _, scope := range scopes {
|
||||||
|
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
|
||||||
|
return scopes, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roles, err := o.repo.ProjectRolesByProjectID(app.ProjectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, role := range roles {
|
||||||
|
scopes = append(scopes, ScopeProjectRolePrefix+role.Key)
|
||||||
|
}
|
||||||
|
return scopes, nil
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package oidc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
user_model "github.com/caos/zitadel/internal/user/model"
|
user_model "github.com/caos/zitadel/internal/user/model"
|
||||||
|
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -24,6 +26,9 @@ const (
|
|||||||
scopePhone = "phone"
|
scopePhone = "phone"
|
||||||
scopeAddress = "address"
|
scopeAddress = "address"
|
||||||
|
|
||||||
|
ScopeProjectRolePrefix = "urn:zitadel:iam:org:project:role:"
|
||||||
|
ClaimProjectRoles = "urn:zitadel:iam:org:project:roles"
|
||||||
|
|
||||||
oidcCtx = "oidc"
|
oidcCtx = "oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,7 +40,15 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Clie
|
|||||||
if client.State != proj_model.AppStateActive {
|
if client.State != proj_model.AppStateActive {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sdaGg", "client is not active")
|
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sdaGg", "client is not active")
|
||||||
}
|
}
|
||||||
return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime)
|
projectRoles, err := o.repo.ProjectRolesByProjectID(client.ProjectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
allowedScopes := make([]string, len(projectRoles))
|
||||||
|
for i, role := range projectRoles {
|
||||||
|
allowedScopes[i] = ScopeProjectRolePrefix + role.Key
|
||||||
|
}
|
||||||
|
return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime, allowedScopes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error) {
|
func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error) {
|
||||||
@ -65,10 +78,10 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
|
|||||||
return o.repo.AuthorizeOIDCApplication(ctx, id, secret)
|
return o.repo.AuthorizeOIDCApplication(ctx, id, secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (*oidc.Userinfo, error) {
|
func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (oidc.UserInfo, error) {
|
||||||
token, err := o.repo.TokenByID(ctx, tokenID, subject)
|
token, err := o.repo.TokenByID(ctx, subject, tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
|
||||||
}
|
}
|
||||||
if token.ApplicationID != "" {
|
if token.ApplicationID != "" {
|
||||||
app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID)
|
app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID)
|
||||||
@ -79,65 +92,126 @@ func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject,
|
|||||||
return nil, errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
|
return nil, errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return o.GetUserinfoFromScopes(ctx, token.UserID, token.Scopes)
|
return o.GetUserinfoFromScopes(ctx, token.UserID, token.ApplicationID, token.Scopes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, scopes []string) (*oidc.Userinfo, error) {
|
func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (oidc.UserInfo, error) {
|
||||||
user, err := o.repo.UserByID(ctx, userID)
|
user, err := o.repo.UserByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
userInfo := new(oidc.Userinfo)
|
userInfo := oidc.NewUserInfo()
|
||||||
|
roles := make([]string, 0)
|
||||||
for _, scope := range scopes {
|
for _, scope := range scopes {
|
||||||
switch scope {
|
switch scope {
|
||||||
case scopeOpenID:
|
case oidc.ScopeOpenID:
|
||||||
userInfo.Subject = user.ID
|
userInfo.SetSubject(user.ID)
|
||||||
case scopeEmail:
|
case oidc.ScopeEmail:
|
||||||
if user.HumanView == nil {
|
if user.HumanView == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
userInfo.Email = user.Email
|
userInfo.SetEmail(user.Email, user.IsEmailVerified)
|
||||||
userInfo.EmailVerified = user.IsEmailVerified
|
case oidc.ScopeProfile:
|
||||||
case scopeProfile:
|
userInfo.SetPreferredUsername(user.PreferredLoginName)
|
||||||
userInfo.PreferredUsername = user.PreferredLoginName
|
userInfo.SetUpdatedAt(user.ChangeDate)
|
||||||
userInfo.UpdatedAt = user.ChangeDate
|
|
||||||
if user.HumanView != nil {
|
if user.HumanView != nil {
|
||||||
userInfo.Name = user.DisplayName
|
userInfo.SetName(user.DisplayName)
|
||||||
userInfo.FamilyName = user.LastName
|
userInfo.SetFamilyName(user.LastName)
|
||||||
userInfo.GivenName = user.FirstName
|
userInfo.SetGivenName(user.FirstName)
|
||||||
userInfo.Nickname = user.NickName
|
userInfo.SetNickname(user.NickName)
|
||||||
userInfo.Gender = oidc.Gender(getGender(user.Gender))
|
userInfo.SetGender(oidc.Gender(getGender(user.Gender)))
|
||||||
userInfo.Locale, err = language.Parse(user.PreferredLanguage)
|
locale, _ := language.Parse(user.PreferredLanguage)
|
||||||
|
userInfo.SetLocale(locale)
|
||||||
} else {
|
} else {
|
||||||
userInfo.Name = user.MachineView.Name
|
userInfo.SetName(user.MachineView.Name)
|
||||||
}
|
}
|
||||||
case scopePhone:
|
case oidc.ScopePhone:
|
||||||
if user.HumanView == nil {
|
if user.HumanView == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
userInfo.PhoneNumber = user.Phone
|
userInfo.SetPhone(user.Phone, user.IsPhoneVerified)
|
||||||
userInfo.PhoneNumberVerified = user.IsPhoneVerified
|
case oidc.ScopeAddress:
|
||||||
case scopeAddress:
|
|
||||||
if user.HumanView == nil {
|
if user.HumanView == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if user.StreetAddress == "" && user.Locality == "" && user.Region == "" && user.PostalCode == "" && user.Country == "" {
|
if user.StreetAddress == "" && user.Locality == "" && user.Region == "" && user.PostalCode == "" && user.Country == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
userInfo.Address = &oidc.UserinfoAddress{
|
userInfo.SetAddress(oidc.NewUserInfoAddress(user.StreetAddress, user.Locality, user.Region, user.PostalCode, user.Country, ""))
|
||||||
StreetAddress: user.StreetAddress,
|
|
||||||
Locality: user.Locality,
|
|
||||||
Region: user.Region,
|
|
||||||
PostalCode: user.PostalCode,
|
|
||||||
Country: user.Country,
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
userInfo.Authorizations = append(userInfo.Authorizations, scope)
|
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
|
||||||
|
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(roles) == 0 || applicationID == "" {
|
||||||
|
return userInfo, nil
|
||||||
|
}
|
||||||
|
projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(projectRoles) > 0 {
|
||||||
|
userInfo.AppendClaims(ClaimProjectRoles, projectRoles)
|
||||||
|
}
|
||||||
|
|
||||||
return userInfo, nil
|
return userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (claims map[string]interface{}, err error) {
|
||||||
|
roles := make([]string, 0)
|
||||||
|
for _, scope := range scopes {
|
||||||
|
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
|
||||||
|
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(roles) == 0 || applicationID == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(projectRoles) > 0 {
|
||||||
|
claims = map[string]interface{}{ClaimProjectRoles: projectRoles}
|
||||||
|
}
|
||||||
|
return claims, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID string, requestedRoles []string) (map[string]map[string]string, error) {
|
||||||
|
app, err := o.repo.ApplicationByClientID(ctx, applicationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
grants, err := o.repo.UserGrantsByProjectAndUserID(app.ProjectID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
projectRoles := make(map[string]map[string]string)
|
||||||
|
for _, requestedRole := range requestedRoles {
|
||||||
|
for _, grant := range grants {
|
||||||
|
checkGrantedRoles(projectRoles, grant, requestedRole)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return projectRoles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkGrantedRoles(roles map[string]map[string]string, grant *grant_model.UserGrantView, requestedRole string) {
|
||||||
|
for _, grantedRole := range grant.RoleKeys {
|
||||||
|
if requestedRole == grantedRole {
|
||||||
|
appendRole(roles, grantedRole, grant.ResourceOwner, grant.OrgPrimaryDomain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendRole(roles map[string]map[string]string, role, orgID, orgPrimaryDomain string) {
|
||||||
|
if roles[role] == nil {
|
||||||
|
roles[role] = make(map[string]string, 0)
|
||||||
|
}
|
||||||
|
roles[role][orgID] = orgPrimaryDomain
|
||||||
|
}
|
||||||
|
|
||||||
func getGender(gender user_model.Gender) string {
|
func getGender(gender user_model.Gender) string {
|
||||||
switch gender {
|
switch gender {
|
||||||
case user_model.GenderFemale:
|
case user_model.GenderFemale:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
"github.com/caos/oidc/pkg/op"
|
"github.com/caos/oidc/pkg/op"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
@ -15,13 +15,20 @@ type Client struct {
|
|||||||
defaultLoginURL string
|
defaultLoginURL string
|
||||||
defaultAccessTokenLifetime time.Duration
|
defaultAccessTokenLifetime time.Duration
|
||||||
defaultIdTokenLifetime time.Duration
|
defaultIdTokenLifetime time.Duration
|
||||||
|
allowedScopes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration) (op.Client, error) {
|
func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration, allowedScopes []string) (op.Client, error) {
|
||||||
if !app.IsOIDC {
|
if !app.IsOIDC {
|
||||||
return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application")
|
return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application")
|
||||||
}
|
}
|
||||||
return &Client{ApplicationView: app, defaultLoginURL: defaultLoginURL, defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultIdTokenLifetime: defaultIdTokenLifetime}, nil
|
return &Client{
|
||||||
|
ApplicationView: app,
|
||||||
|
defaultLoginURL: defaultLoginURL,
|
||||||
|
defaultAccessTokenLifetime: defaultAccessTokenLifetime,
|
||||||
|
defaultIdTokenLifetime: defaultIdTokenLifetime,
|
||||||
|
allowedScopes: allowedScopes},
|
||||||
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ApplicationType() op.ApplicationType {
|
func (c *Client) ApplicationType() op.ApplicationType {
|
||||||
@ -56,6 +63,18 @@ func (c *Client) DevMode() bool {
|
|||||||
return c.ApplicationView.DevMode
|
return c.ApplicationView.DevMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) AllowedScopes() []string {
|
||||||
|
return c.allowedScopes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssertAdditionalIdTokenScopes() bool {
|
||||||
|
return c.IDTokenRoleAssertion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssertAdditionalAccessTokenScopes() bool {
|
||||||
|
return c.AccessTokenRoleAssertion
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) AccessTokenLifetime() time.Duration {
|
func (c *Client) AccessTokenLifetime() time.Duration {
|
||||||
return c.defaultAccessTokenLifetime //PLANNED: impl from real client
|
return c.defaultAccessTokenLifetime //PLANNED: impl from real client
|
||||||
}
|
}
|
||||||
@ -65,7 +84,18 @@ func (c *Client) IDTokenLifetime() time.Duration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) AccessTokenType() op.AccessTokenType {
|
func (c *Client) AccessTokenType() op.AccessTokenType {
|
||||||
return op.AccessTokenTypeBearer //PLANNED: impl from real client
|
return accessTokenTypeToOIDC(c.ApplicationView.AccessTokenType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func accessTokenTypeToOIDC(tokenType model.OIDCTokenType) op.AccessTokenType {
|
||||||
|
switch tokenType {
|
||||||
|
case model.OIDCTokenTypeBearer:
|
||||||
|
return op.AccessTokenTypeBearer
|
||||||
|
case model.OIDCTokenTypeJWT:
|
||||||
|
return op.AccessTokenTypeJWT
|
||||||
|
default:
|
||||||
|
return op.AccessTokenTypeBearer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod {
|
func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod {
|
||||||
|
@ -2,28 +2,30 @@ package eventstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/caos/zitadel/internal/api/authz"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore/sdk"
|
|
||||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
|
||||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
|
||||||
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/auth_request/model"
|
"github.com/caos/zitadel/internal/auth_request/model"
|
||||||
cache "github.com/caos/zitadel/internal/auth_request/repository"
|
cache "github.com/caos/zitadel/internal/auth_request/repository"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/sdk"
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
"github.com/caos/zitadel/internal/id"
|
"github.com/caos/zitadel/internal/id"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||||
|
project_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
user_model "github.com/caos/zitadel/internal/user/model"
|
user_model "github.com/caos/zitadel/internal/user/model"
|
||||||
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||||
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
|
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthRequestRepo struct {
|
type AuthRequestRepo struct {
|
||||||
@ -38,6 +40,7 @@ type AuthRequestRepo struct {
|
|||||||
OrgViewProvider orgViewProvider
|
OrgViewProvider orgViewProvider
|
||||||
LoginPolicyViewProvider loginPolicyViewProvider
|
LoginPolicyViewProvider loginPolicyViewProvider
|
||||||
IDPProviderViewProvider idpProviderViewProvider
|
IDPProviderViewProvider idpProviderViewProvider
|
||||||
|
UserGrantProvider userGrantProvider
|
||||||
|
|
||||||
IdGenerator id.Generator
|
IdGenerator id.Generator
|
||||||
|
|
||||||
@ -76,6 +79,11 @@ type orgViewProvider interface {
|
|||||||
OrgByPrimaryDomain(string) (*org_view_model.OrgView, error)
|
OrgByPrimaryDomain(string) (*org_view_model.OrgView, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type userGrantProvider interface {
|
||||||
|
ApplicationByClientID(context.Context, string) (*project_view_model.ApplicationView, error)
|
||||||
|
UserGrantsByProjectAndUserID(string, string) ([]*grant_view_model.UserGrantView, error)
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
|
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
|
||||||
if err := repo.UserEvents.Health(ctx); err != nil {
|
if err := repo.UserEvents.Health(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -89,14 +97,18 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
request.ID = reqID
|
request.ID = reqID
|
||||||
ids, err := repo.View.AppIDsFromProjectByClientID(ctx, request.ApplicationID)
|
app, err := repo.View.ApplicationByClientID(ctx, request.ApplicationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
request.Audience = ids
|
appIDs, err := repo.View.AppIDsFromProjectID(ctx, app.ProjectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.Audience = appIDs
|
||||||
if request.LoginHint != "" {
|
if request.LoginHint != "" {
|
||||||
err = repo.checkLoginName(ctx, request, request.LoginHint)
|
err = repo.checkLoginName(ctx, request, request.LoginHint)
|
||||||
logging.LogWithFields("EVENT-aG311", "login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID).Debug("login hint invalid")
|
logging.LogWithFields("EVENT-aG311", "login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID).OnError(err).Debug("login hint invalid")
|
||||||
}
|
}
|
||||||
err = repo.AuthRequests.SaveAuthRequest(ctx, request)
|
err = repo.AuthRequests.SaveAuthRequest(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -541,6 +553,15 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
|
|||||||
|
|
||||||
}
|
}
|
||||||
//PLANNED: consent step
|
//PLANNED: consent step
|
||||||
|
|
||||||
|
missing, err := userGrantRequired(ctx, request, user, repo.UserGrantProvider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if missing {
|
||||||
|
return append(steps, &model.GrantRequiredStep{}), nil
|
||||||
|
}
|
||||||
|
|
||||||
return append(steps, &model.RedirectToCallbackStep{}), nil
|
return append(steps, &model.RedirectToCallbackStep{}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,3 +801,23 @@ func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*model.ExternalUser, i
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
func userGrantRequired(ctx context.Context, request *model.AuthRequest, user *user_model.UserView, userGrantProvider userGrantProvider) (_ bool, err error) {
|
||||||
|
var app *project_view_model.ApplicationView
|
||||||
|
switch request.Request.Type() {
|
||||||
|
case model.AuthRequestTypeOIDC:
|
||||||
|
app, err = userGrantProvider.ApplicationByClientID(ctx, request.ApplicationID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false, errors.ThrowPreconditionFailed(nil, "EVENT-dfrw2", "Errors.AuthRequest.RequestTypeNotSupported")
|
||||||
|
}
|
||||||
|
if !app.ProjectRoleCheck {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
grants, err := userGrantProvider.UserGrantsByProjectAndUserID(app.ProjectID, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return len(grants) == 0, nil
|
||||||
|
}
|
||||||
|
@ -15,10 +15,12 @@ import (
|
|||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
|
||||||
|
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
user_model "github.com/caos/zitadel/internal/user/model"
|
user_model "github.com/caos/zitadel/internal/user/model"
|
||||||
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||||
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
|
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockViewNoUserSession struct{}
|
type mockViewNoUserSession struct{}
|
||||||
@ -157,6 +159,23 @@ func (m *mockViewErrOrg) OrgByPrimaryDomain(string) (*org_view_model.OrgView, er
|
|||||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockUserGrants struct {
|
||||||
|
roleCheck bool
|
||||||
|
userGrants int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockUserGrants) ApplicationByClientID(ctx context.Context, s string) (*proj_view_model.ApplicationView, error) {
|
||||||
|
return &proj_view_model.ApplicationView{ProjectRoleCheck: m.roleCheck}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*grant_view_model.UserGrantView, error) {
|
||||||
|
var grants []*grant_view_model.UserGrantView
|
||||||
|
if m.userGrants > 0 {
|
||||||
|
grants = make([]*grant_view_model.UserGrantView, m.userGrants)
|
||||||
|
}
|
||||||
|
return grants, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UserEvents *user_event.UserEventstore
|
UserEvents *user_event.UserEventstore
|
||||||
@ -166,6 +185,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
userViewProvider userViewProvider
|
userViewProvider userViewProvider
|
||||||
userEventProvider userEventProvider
|
userEventProvider userEventProvider
|
||||||
orgViewProvider orgViewProvider
|
orgViewProvider orgViewProvider
|
||||||
|
userGrantProvider userGrantProvider
|
||||||
PasswordCheckLifeTime time.Duration
|
PasswordCheckLifeTime time.Duration
|
||||||
ExternalLoginCheckLifeTime time.Duration
|
ExternalLoginCheckLifeTime time.Duration
|
||||||
MfaInitSkippedLifeTime time.Duration
|
MfaInitSkippedLifeTime time.Duration
|
||||||
@ -424,10 +444,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
|
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
|
||||||
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -460,10 +481,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
},
|
},
|
||||||
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
|
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
|
||||||
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -590,10 +612,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
args{&model.AuthRequest{UserID: "UserID"}, false},
|
args{&model.AuthRequest{UserID: "UserID", Request: &model.AuthRequestOIDC{}}, false},
|
||||||
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -611,10 +634,61 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone}, true},
|
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
|
||||||
|
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prompt none, checkLoggedIn true, authenticated and required user grants missing, grant required step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
|
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
},
|
||||||
|
userViewProvider: &mockViewUser{
|
||||||
|
PasswordSet: true,
|
||||||
|
IsEmailVerified: true,
|
||||||
|
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||||
|
},
|
||||||
|
userEventProvider: &mockEventUser{},
|
||||||
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{
|
||||||
|
roleCheck: true,
|
||||||
|
userGrants: 0,
|
||||||
|
},
|
||||||
|
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
|
},
|
||||||
|
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
|
||||||
|
[]model.NextStep{&model.GrantRequiredStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prompt none, checkLoggedIn true, authenticated and required user grants exist, redirect to callback step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
|
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
},
|
||||||
|
userViewProvider: &mockViewUser{
|
||||||
|
PasswordSet: true,
|
||||||
|
IsEmailVerified: true,
|
||||||
|
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||||
|
},
|
||||||
|
userEventProvider: &mockEventUser{},
|
||||||
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
userGrantProvider: &mockUserGrants{
|
||||||
|
roleCheck: true,
|
||||||
|
userGrants: 2,
|
||||||
|
},
|
||||||
|
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
|
},
|
||||||
|
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
|
||||||
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
[]model.NextStep{&model.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -679,6 +753,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
UserViewProvider: tt.fields.userViewProvider,
|
UserViewProvider: tt.fields.userViewProvider,
|
||||||
UserEventProvider: tt.fields.userEventProvider,
|
UserEventProvider: tt.fields.userEventProvider,
|
||||||
OrgViewProvider: tt.fields.orgViewProvider,
|
OrgViewProvider: tt.fields.orgViewProvider,
|
||||||
|
UserGrantProvider: tt.fields.userGrantProvider,
|
||||||
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
|
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
|
||||||
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
|
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
|
||||||
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
|
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
|
||||||
|
21
internal/auth/repository/eventsourcing/eventstore/project.go
Normal file
21
internal/auth/repository/eventsourcing/eventstore/project.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package eventstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
|
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
|
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectRepo struct {
|
||||||
|
View *view.View
|
||||||
|
ProjectEvents *proj_event.ProjectEventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplicationRepo) ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error) {
|
||||||
|
roles, err := a.View.ProjectRolesByProjectID(projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return proj_view_model.ProjectRolesToModel(roles), nil
|
||||||
|
}
|
@ -52,11 +52,27 @@ func (p *Application) Reduce(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
err = app.AppendEvent(event)
|
err = app.AppendEvent(event)
|
||||||
case es_model.ApplicationRemoved:
|
case es_model.ApplicationRemoved:
|
||||||
err := app.SetData(event)
|
err = app.SetData(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p.view.DeleteApplication(app.ID, event.Sequence)
|
return p.view.DeleteApplication(app.ID, event.Sequence)
|
||||||
|
case es_model.ProjectChanged:
|
||||||
|
apps, err := p.view.ApplicationsByProjectID(event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(apps) == 0 {
|
||||||
|
return p.view.ProcessedApplicationSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
for _, app := range apps {
|
||||||
|
if err := app.AppendEvent(event); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.view.PutApplications(apps, event.Sequence)
|
||||||
|
case es_model.ProjectRemoved:
|
||||||
|
return p.view.DeleteApplicationsByProjectID(event.AggregateID)
|
||||||
default:
|
default:
|
||||||
return p.view.ProcessedApplicationSequence(event.Sequence)
|
return p.view.ProcessedApplicationSequence(event.Sequence)
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
|
|||||||
&ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount}, systemDefaults: systemDefaults, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents},
|
&ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount}, systemDefaults: systemDefaults, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents},
|
||||||
&PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
|
&PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
|
||||||
&OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
|
&OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
|
||||||
|
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
|
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
|
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
|
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||||
|
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectRole struct {
|
||||||
|
handler
|
||||||
|
projectEvents *proj_event.ProjectEventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
projectRoleTable = "auth.project_roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *ProjectRole) ViewModel() string {
|
||||||
|
return projectRoleTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) {
|
||||||
|
sequence, err := p.view.GetLatestProjectRoleSequence()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectRole) Reduce(event *models.Event) (err error) {
|
||||||
|
role := new(view_model.ProjectRoleView)
|
||||||
|
switch event.Type {
|
||||||
|
case es_model.ProjectRoleAdded:
|
||||||
|
err = role.AppendEvent(event)
|
||||||
|
case es_model.ProjectRoleChanged:
|
||||||
|
err = role.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
role, err = p.view.ProjectRoleByIDs(event.AggregateID, event.ResourceOwner, role.Key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = role.AppendEvent(event)
|
||||||
|
case es_model.ProjectRoleRemoved:
|
||||||
|
err = role.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence)
|
||||||
|
case es_model.ProjectRemoved:
|
||||||
|
return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
|
||||||
|
default:
|
||||||
|
return p.view.ProcessedProjectRoleSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.view.PutProjectRole(role)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectRole) OnError(event *models.Event, err error) error {
|
||||||
|
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
|
||||||
|
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
|
||||||
|
}
|
@ -354,6 +354,12 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
|||||||
|
|
||||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||||
grant.OrgName = org.Name
|
grant.OrgName = org.Name
|
||||||
|
for _, domain := range org.Domains {
|
||||||
|
if domain.Primary {
|
||||||
|
grant.OrgPrimaryDomain = domain.Domain
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
||||||
|
@ -107,7 +107,7 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
|
|||||||
case org_es_model.OrgMemberRemoved:
|
case org_es_model.OrgMemberRemoved:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
|
||||||
case org_es_model.OrgChanged:
|
case org_es_model.OrgChanged:
|
||||||
err = m.updateOrgName(event)
|
return m.updateOrgName(event)
|
||||||
default:
|
default:
|
||||||
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
||||||
}
|
}
|
||||||
@ -178,7 +178,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
|
|||||||
case proj_es_model.ProjectGrantMemberRemoved:
|
case proj_es_model.ProjectGrantMemberRemoved:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
|
||||||
case proj_es_model.ProjectChanged:
|
case proj_es_model.ProjectChanged:
|
||||||
err = m.updateProjectDisplayName(event)
|
return m.updateProjectDisplayName(event)
|
||||||
case proj_es_model.ProjectRemoved:
|
case proj_es_model.ProjectRemoved:
|
||||||
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
|
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
|
||||||
case proj_es_model.ProjectGrantRemoved:
|
case proj_es_model.ProjectGrantRemoved:
|
||||||
@ -227,6 +227,6 @@ func (m *UserMembership) processUser(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) OnError(event *models.Event, err error) error {
|
func (m *UserMembership) OnError(event *models.Event, err error) error {
|
||||||
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
|
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)
|
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
|
|||||||
OrgViewProvider: view,
|
OrgViewProvider: view,
|
||||||
IDPProviderViewProvider: view,
|
IDPProviderViewProvider: view,
|
||||||
LoginPolicyViewProvider: view,
|
LoginPolicyViewProvider: view,
|
||||||
|
UserGrantProvider: view,
|
||||||
IdGenerator: idGenerator,
|
IdGenerator: idGenerator,
|
||||||
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
|
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
|
||||||
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
|
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
|
||||||
@ -156,6 +157,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
|
|||||||
View: view,
|
View: view,
|
||||||
ProjectEvents: project,
|
ProjectEvents: project,
|
||||||
},
|
},
|
||||||
|
|
||||||
eventstore.UserSessionRepo{
|
eventstore.UserSessionRepo{
|
||||||
View: view,
|
View: view,
|
||||||
},
|
},
|
||||||
|
@ -18,16 +18,28 @@ func (v *View) ApplicationByID(projectID, appID string) (*model.ApplicationView,
|
|||||||
return view.ApplicationByID(v.Db, applicationTable, projectID, appID)
|
return view.ApplicationByID(v.Db, applicationTable, projectID, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) ApplicationsByProjectID(projectID string) ([]*model.ApplicationView, error) {
|
||||||
|
return view.ApplicationsByProjectID(v.Db, applicationTable, projectID)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
|
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
|
||||||
return view.SearchApplications(v.Db, applicationTable, request)
|
return view.SearchApplications(v.Db, applicationTable, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutApplication(project *model.ApplicationView) error {
|
func (v *View) PutApplication(app *model.ApplicationView) error {
|
||||||
err := view.PutApplication(v.Db, applicationTable, project)
|
err := view.PutApplication(v.Db, applicationTable, app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedApplicationSequence(project.Sequence)
|
return v.ProcessedApplicationSequence(app.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64) error {
|
||||||
|
err := view.PutApplications(v.Db, applicationTable, apps...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedApplicationSequence(sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
||||||
@ -38,6 +50,10 @@ func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
|||||||
return v.ProcessedApplicationSequence(eventSequence)
|
return v.ProcessedApplicationSequence(eventSequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
|
||||||
|
return view.DeleteApplicationsByProjectID(v.Db, applicationTable, projectID)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(applicationTable)
|
return v.latestSequence(applicationTable)
|
||||||
}
|
}
|
||||||
@ -55,24 +71,7 @@ func (v *View) ProcessedApplicationFailedEvent(failedEvent *repository.FailedEve
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ApplicationByClientID(_ context.Context, clientID string) (*model.ApplicationView, error) {
|
func (v *View) ApplicationByClientID(_ context.Context, clientID string) (*model.ApplicationView, error) {
|
||||||
req := &proj_model.ApplicationSearchRequest{
|
return view.ApplicationByOIDCClientID(v.Db, applicationTable, clientID)
|
||||||
Limit: 1,
|
|
||||||
Queries: []*proj_model.ApplicationSearchQuery{
|
|
||||||
{
|
|
||||||
Key: proj_model.AppSearchKeyOIDCClientID,
|
|
||||||
Method: global_model.SearchMethodEquals,
|
|
||||||
Value: clientID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
apps, count, err := view.SearchApplications(v.Db, applicationTable, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.ThrowPreconditionFailed(err, "VIEW-sd6JQ", "cannot find client")
|
|
||||||
}
|
|
||||||
if count != 1 {
|
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "VIEW-dfw3as", "cannot find client")
|
|
||||||
}
|
|
||||||
return apps[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string) ([]string, error) {
|
func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string) ([]string, error) {
|
||||||
@ -102,3 +101,27 @@ func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string)
|
|||||||
}
|
}
|
||||||
return ids, nil
|
return ids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) AppIDsFromProjectID(ctx context.Context, projectID string) ([]string, error) {
|
||||||
|
req := &proj_model.ApplicationSearchRequest{
|
||||||
|
Queries: []*proj_model.ApplicationSearchQuery{
|
||||||
|
{
|
||||||
|
Key: proj_model.AppSearchKeyProjectID,
|
||||||
|
Method: global_model.SearchMethodEquals,
|
||||||
|
Value: projectID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
apps, _, err := view.SearchApplications(v.Db, applicationTable, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(err, "VIEW-Gd24q", "cannot find applications")
|
||||||
|
}
|
||||||
|
ids := make([]string, 0, len(apps))
|
||||||
|
for _, app := range apps {
|
||||||
|
if !app.IsOIDC {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ids = append(ids, app.OIDCClientID)
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
68
internal/auth/repository/eventsourcing/view/project_role.go
Normal file
68
internal/auth/repository/eventsourcing/view/project_role.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
|
"github.com/caos/zitadel/internal/project/repository/view"
|
||||||
|
"github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
projectRoleTable = "auth.project_roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) ProjectRoleByIDs(projectID, orgID, key string) (*model.ProjectRoleView, error) {
|
||||||
|
return view.ProjectRoleByIDs(v.Db, projectRoleTable, projectID, orgID, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error) {
|
||||||
|
return view.ProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ResourceOwnerProjectRolesByKey(projectID, resourceowner, key string) ([]*model.ProjectRoleView, error) {
|
||||||
|
return view.ResourceOwnerProjectRolesByKey(v.Db, projectRoleTable, projectID, resourceowner, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ResourceOwnerProjectRoles(projectID, resourceowner string) ([]*model.ProjectRoleView, error) {
|
||||||
|
return view.ResourceOwnerProjectRoles(v.Db, projectRoleTable, projectID, resourceowner)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest) ([]*model.ProjectRoleView, uint64, error) {
|
||||||
|
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutProjectRole(project *model.ProjectRoleView) error {
|
||||||
|
err := view.PutProjectRole(v.Db, projectRoleTable, project)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedProjectRoleSequence(project.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64) error {
|
||||||
|
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.ProcessedProjectRoleSequence(eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
|
||||||
|
return view.DeleteProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequence(projectRoleTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedProjectRoleSequence(eventSequence uint64) error {
|
||||||
|
return v.saveCurrentSequence(projectRoleTable, eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestProjectRoleFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
||||||
|
return v.latestFailedEvent(projectRoleTable, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedProjectRoleFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
return v.saveFailedEvent(failedEvent)
|
||||||
|
}
|
@ -36,7 +36,7 @@ func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
|
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
|
||||||
err := view.PutUserMemberships(v.Db, userTable, memberships...)
|
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
9
internal/auth/repository/project.go
Normal file
9
internal/auth/repository/project.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectRepository interface {
|
||||||
|
ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error)
|
||||||
|
}
|
@ -10,6 +10,7 @@ type Repository interface {
|
|||||||
AuthRequestRepository
|
AuthRequestRepository
|
||||||
TokenRepository
|
TokenRepository
|
||||||
ApplicationRepository
|
ApplicationRepository
|
||||||
|
ProjectRepository
|
||||||
KeyRepository
|
KeyRepository
|
||||||
UserSessionRepository
|
UserSessionRepository
|
||||||
UserGrantRepository
|
UserGrantRepository
|
||||||
|
@ -22,6 +22,7 @@ const (
|
|||||||
NextStepLinkUsers
|
NextStepLinkUsers
|
||||||
NextStepExternalNotFoundOption
|
NextStepExternalNotFoundOption
|
||||||
NextStepExternalLogin
|
NextStepExternalLogin
|
||||||
|
NextStepGrantRequired
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserSessionState int32
|
type UserSessionState int32
|
||||||
@ -127,6 +128,12 @@ func (s *LinkUsersStep) Type() NextStepType {
|
|||||||
return NextStepLinkUsers
|
return NextStepLinkUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GrantRequiredStep struct{}
|
||||||
|
|
||||||
|
func (s *GrantRequiredStep) Type() NextStepType {
|
||||||
|
return NextStepGrantRequired
|
||||||
|
}
|
||||||
|
|
||||||
type RedirectToCallbackStep struct{}
|
type RedirectToCallbackStep struct{}
|
||||||
|
|
||||||
func (s *RedirectToCallbackStep) Type() NextStepType {
|
func (s *RedirectToCallbackStep) Type() NextStepType {
|
||||||
|
@ -68,13 +68,12 @@ func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (*proj_mode
|
|||||||
return model.ProjectToModel(project), nil
|
return model.ProjectToModel(project), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) CreateProject(ctx context.Context, name string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) CreateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
ctxData := authz.GetCtxData(ctx)
|
ctxData := authz.GetCtxData(ctx)
|
||||||
iam, err := repo.IAMEvents.IAMByID(ctx, repo.IAMID)
|
iam, err := repo.IAMEvents.IAMByID(ctx, repo.IAMID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
project := &proj_model.Project{Name: name}
|
|
||||||
return repo.ProjectEvents.CreateProject(ctx, project, iam.GlobalOrgID == ctxData.OrgID)
|
return repo.ProjectEvents.CreateProject(ctx, project, iam.GlobalOrgID == ctxData.OrgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,20 @@ func (p *Application) Reduce(event *models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p.view.DeleteApplication(app.ID, event.Sequence)
|
return p.view.DeleteApplication(app.ID, event.Sequence)
|
||||||
|
case es_model.ProjectChanged:
|
||||||
|
apps, err := p.view.ApplicationsByProjectID(event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(apps) == 0 {
|
||||||
|
return p.view.ProcessedApplicationSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
for _, app := range apps {
|
||||||
|
if err := app.AppendEvent(event); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.view.PutApplications(apps, event.Sequence)
|
||||||
case es_model.ProjectRemoved:
|
case es_model.ProjectRemoved:
|
||||||
return p.view.DeleteApplicationsByProjectID(event.AggregateID)
|
return p.view.DeleteApplicationsByProjectID(event.AggregateID)
|
||||||
default:
|
default:
|
||||||
|
@ -180,6 +180,12 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
|||||||
|
|
||||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||||
grant.OrgName = org.Name
|
grant.OrgName = org.Name
|
||||||
|
for _, domain := range org.Domains {
|
||||||
|
if domain.Primary {
|
||||||
|
grant.OrgPrimaryDomain = domain.Domain
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
||||||
|
@ -105,7 +105,7 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
|
|||||||
case org_es_model.OrgMemberRemoved:
|
case org_es_model.OrgMemberRemoved:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
|
||||||
case org_es_model.OrgChanged:
|
case org_es_model.OrgChanged:
|
||||||
err = m.updateOrgDisplayName(event)
|
return m.updateOrgDisplayName(event)
|
||||||
default:
|
default:
|
||||||
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
|
|||||||
case proj_es_model.ProjectGrantMemberRemoved:
|
case proj_es_model.ProjectGrantMemberRemoved:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
|
||||||
case proj_es_model.ProjectChanged:
|
case proj_es_model.ProjectChanged:
|
||||||
err = m.updateProjectDisplayName(event)
|
return m.updateProjectDisplayName(event)
|
||||||
case proj_es_model.ProjectRemoved:
|
case proj_es_model.ProjectRemoved:
|
||||||
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
|
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
|
||||||
case proj_es_model.ProjectGrantRemoved:
|
case proj_es_model.ProjectGrantRemoved:
|
||||||
@ -215,6 +215,6 @@ func (m *UserMembership) processUser(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) OnError(event *models.Event, err error) error {
|
func (m *UserMembership) OnError(event *models.Event, err error) error {
|
||||||
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
|
logging.LogWithFields("SPOOL-Fwer2", "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)
|
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
|
||||||
}
|
}
|
||||||
|
@ -15,20 +15,28 @@ func (v *View) ApplicationByID(projectID, appID string) (*model.ApplicationView,
|
|||||||
return view.ApplicationByID(v.Db, applicationTable, projectID, appID)
|
return view.ApplicationByID(v.Db, applicationTable, projectID, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ApplicationsByProjectID(ProjectID string) ([]*model.ApplicationView, error) {
|
func (v *View) ApplicationsByProjectID(projectID string) ([]*model.ApplicationView, error) {
|
||||||
return view.ApplicationsByProjectID(v.Db, applicationTable, ProjectID)
|
return view.ApplicationsByProjectID(v.Db, applicationTable, projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
|
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
|
||||||
return view.SearchApplications(v.Db, applicationTable, request)
|
return view.SearchApplications(v.Db, applicationTable, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutApplication(project *model.ApplicationView) error {
|
func (v *View) PutApplication(app *model.ApplicationView) error {
|
||||||
err := view.PutApplication(v.Db, applicationTable, project)
|
err := view.PutApplication(v.Db, applicationTable, app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedApplicationSequence(project.Sequence)
|
return v.ProcessedApplicationSequence(app.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64) error {
|
||||||
|
err := view.PutApplications(v.Db, applicationTable, apps...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedApplicationSequence(sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
||||||
@ -39,8 +47,8 @@ func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
|
|||||||
return v.ProcessedApplicationSequence(eventSequence)
|
return v.ProcessedApplicationSequence(eventSequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteApplicationsByProjectID(ProjectID string) error {
|
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
|
||||||
return view.DeleteApplicationsByProjectID(v.Db, applicationTable, ProjectID)
|
return view.DeleteApplicationsByProjectID(v.Db, applicationTable, projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
|
||||||
|
@ -32,7 +32,7 @@ func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
|
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
|
||||||
err := view.PutUserMemberships(v.Db, userTable, memberships...)
|
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
type ProjectRepository interface {
|
type ProjectRepository interface {
|
||||||
ProjectByID(ctx context.Context, id string) (*model.ProjectView, error)
|
ProjectByID(ctx context.Context, id string) (*model.ProjectView, error)
|
||||||
CreateProject(ctx context.Context, name string) (*model.Project, error)
|
CreateProject(ctx context.Context, project *model.Project) (*model.Project, error)
|
||||||
UpdateProject(ctx context.Context, project *model.Project) (*model.Project, error)
|
UpdateProject(ctx context.Context, project *model.Project) (*model.Project, error)
|
||||||
DeactivateProject(ctx context.Context, id string) (*model.Project, error)
|
DeactivateProject(ctx context.Context, id string) (*model.Project, error)
|
||||||
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
|
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
|
||||||
|
@ -7,12 +7,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ApplicationView struct {
|
type ApplicationView struct {
|
||||||
ID string
|
ID string
|
||||||
ProjectID string
|
ProjectID string
|
||||||
Name string
|
Name string
|
||||||
CreationDate time.Time
|
CreationDate time.Time
|
||||||
ChangeDate time.Time
|
ChangeDate time.Time
|
||||||
State AppState
|
State AppState
|
||||||
|
ProjectRoleAssertion bool
|
||||||
|
ProjectRoleCheck bool
|
||||||
|
|
||||||
IsOIDC bool
|
IsOIDC bool
|
||||||
OIDCVersion OIDCVersion
|
OIDCVersion OIDCVersion
|
||||||
@ -27,6 +29,9 @@ type ApplicationView struct {
|
|||||||
ComplianceProblems []string
|
ComplianceProblems []string
|
||||||
DevMode bool
|
DevMode bool
|
||||||
OriginAllowList []string
|
OriginAllowList []string
|
||||||
|
AccessTokenType OIDCTokenType
|
||||||
|
IDTokenRoleAssertion bool
|
||||||
|
AccessTokenRoleAssertion bool
|
||||||
|
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,22 @@ const (
|
|||||||
|
|
||||||
type OIDCConfig struct {
|
type OIDCConfig struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
AppID string
|
AppID string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
ClientSecret *crypto.CryptoValue
|
||||||
ClientSecretString string
|
ClientSecretString string
|
||||||
RedirectUris []string
|
RedirectUris []string
|
||||||
ResponseTypes []OIDCResponseType
|
ResponseTypes []OIDCResponseType
|
||||||
GrantTypes []OIDCGrantType
|
GrantTypes []OIDCGrantType
|
||||||
ApplicationType OIDCApplicationType
|
ApplicationType OIDCApplicationType
|
||||||
AuthMethodType OIDCAuthMethodType
|
AuthMethodType OIDCAuthMethodType
|
||||||
PostLogoutRedirectUris []string
|
PostLogoutRedirectUris []string
|
||||||
OIDCVersion OIDCVersion
|
OIDCVersion OIDCVersion
|
||||||
Compliance *Compliance
|
Compliance *Compliance
|
||||||
DevMode bool
|
DevMode bool
|
||||||
|
AccessTokenType OIDCTokenType
|
||||||
|
AccessTokenRoleAssertion bool
|
||||||
|
IDTokenRoleAssertion bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type OIDCVersion int32
|
type OIDCVersion int32
|
||||||
@ -79,6 +82,13 @@ type Compliance struct {
|
|||||||
Problems []string
|
Problems []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OIDCTokenType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
OIDCTokenTypeBearer OIDCTokenType = iota
|
||||||
|
OIDCTokenTypeJWT
|
||||||
|
)
|
||||||
|
|
||||||
func (c *OIDCConfig) IsValid() bool {
|
func (c *OIDCConfig) IsValid() bool {
|
||||||
grantTypes := c.getRequiredGrantTypes()
|
grantTypes := c.getRequiredGrantTypes()
|
||||||
for _, grantType := range grantTypes {
|
for _, grantType := range grantTypes {
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
|
||||||
"github.com/golang/protobuf/ptypes/timestamp"
|
"github.com/golang/protobuf/ptypes/timestamp"
|
||||||
|
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
|
|
||||||
State ProjectState
|
State ProjectState
|
||||||
Name string
|
Name string
|
||||||
Members []*ProjectMember
|
Members []*ProjectMember
|
||||||
Roles []*ProjectRole
|
Roles []*ProjectRole
|
||||||
Applications []*Application
|
Applications []*Application
|
||||||
Grants []*ProjectGrant
|
Grants []*ProjectGrant
|
||||||
|
ProjectRoleAssertion bool
|
||||||
|
ProjectRoleCheck bool
|
||||||
}
|
}
|
||||||
type ProjectChanges struct {
|
type ProjectChanges struct {
|
||||||
Changes []*ProjectChange
|
Changes []*ProjectChange
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/caos/zitadel/internal/model"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectView struct {
|
type ProjectView struct {
|
||||||
ProjectID string
|
ProjectID string
|
||||||
Name string
|
Name string
|
||||||
CreationDate time.Time
|
CreationDate time.Time
|
||||||
ChangeDate time.Time
|
ChangeDate time.Time
|
||||||
State ProjectState
|
State ProjectState
|
||||||
ResourceOwner string
|
ResourceOwner string
|
||||||
Sequence uint64
|
ProjectRoleAssertion bool
|
||||||
|
ProjectRoleCheck bool
|
||||||
|
Sequence uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectViewSearchRequest struct {
|
type ProjectViewSearchRequest struct {
|
||||||
|
@ -321,7 +321,7 @@ func (es *ProjectEventstore) AddProjectRoles(ctx context.Context, roles ...*proj
|
|||||||
}
|
}
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if !role.IsValid() {
|
if !role.IsValid() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-idue3", "Errors.Project.MemberInvalid")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-iduG4", "Errors.Project.RoleInvalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
existingProject, err := es.ProjectByID(ctx, roles[0].AggregateID)
|
existingProject, err := es.ProjectByID(ctx, roles[0].AggregateID)
|
||||||
|
@ -2,26 +2,31 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
"reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OIDCConfig struct {
|
type OIDCConfig struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
Version int32 `json:"oidcVersion,omitempty"`
|
Version int32 `json:"oidcVersion,omitempty"`
|
||||||
AppID string `json:"appId"`
|
AppID string `json:"appId"`
|
||||||
ClientID string `json:"clientId,omitempty"`
|
ClientID string `json:"clientId,omitempty"`
|
||||||
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
||||||
RedirectUris []string `json:"redirectUris,omitempty"`
|
RedirectUris []string `json:"redirectUris,omitempty"`
|
||||||
ResponseTypes []int32 `json:"responseTypes,omitempty"`
|
ResponseTypes []int32 `json:"responseTypes,omitempty"`
|
||||||
GrantTypes []int32 `json:"grantTypes,omitempty"`
|
GrantTypes []int32 `json:"grantTypes,omitempty"`
|
||||||
ApplicationType int32 `json:"applicationType,omitempty"`
|
ApplicationType int32 `json:"applicationType,omitempty"`
|
||||||
AuthMethodType int32 `json:"authMethodType,omitempty"`
|
AuthMethodType int32 `json:"authMethodType,omitempty"`
|
||||||
PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"`
|
PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"`
|
||||||
DevMode bool `json:"devMode,omitempty"`
|
DevMode bool `json:"devMode,omitempty"`
|
||||||
|
AccessTokenType int32 `json:"accessTokenType,omitempty"`
|
||||||
|
AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion,omitempty"`
|
||||||
|
IDTokenRoleAssertion bool `json:"idTokenRoleAssertion,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
|
func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
|
||||||
@ -51,6 +56,15 @@ func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
|
|||||||
if c.DevMode != changed.DevMode {
|
if c.DevMode != changed.DevMode {
|
||||||
changes["devMode"] = changed.DevMode
|
changes["devMode"] = changed.DevMode
|
||||||
}
|
}
|
||||||
|
if c.AccessTokenType != changed.AccessTokenType {
|
||||||
|
changes["accessTokenType"] = changed.AccessTokenType
|
||||||
|
}
|
||||||
|
if c.AccessTokenRoleAssertion != changed.AccessTokenRoleAssertion {
|
||||||
|
changes["accessTokenRoleAssertion"] = changed.AccessTokenRoleAssertion
|
||||||
|
}
|
||||||
|
if c.IDTokenRoleAssertion != changed.IDTokenRoleAssertion {
|
||||||
|
changes["idTokenRoleAssertion"] = changed.IDTokenRoleAssertion
|
||||||
|
}
|
||||||
return changes
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,18 +78,21 @@ func OIDCConfigFromModel(config *model.OIDCConfig) *OIDCConfig {
|
|||||||
grantTypes[i] = int32(rt)
|
grantTypes[i] = int32(rt)
|
||||||
}
|
}
|
||||||
return &OIDCConfig{
|
return &OIDCConfig{
|
||||||
ObjectRoot: config.ObjectRoot,
|
ObjectRoot: config.ObjectRoot,
|
||||||
AppID: config.AppID,
|
AppID: config.AppID,
|
||||||
Version: int32(config.OIDCVersion),
|
Version: int32(config.OIDCVersion),
|
||||||
ClientID: config.ClientID,
|
ClientID: config.ClientID,
|
||||||
ClientSecret: config.ClientSecret,
|
ClientSecret: config.ClientSecret,
|
||||||
RedirectUris: config.RedirectUris,
|
RedirectUris: config.RedirectUris,
|
||||||
ResponseTypes: responseTypes,
|
ResponseTypes: responseTypes,
|
||||||
GrantTypes: grantTypes,
|
GrantTypes: grantTypes,
|
||||||
ApplicationType: int32(config.ApplicationType),
|
ApplicationType: int32(config.ApplicationType),
|
||||||
AuthMethodType: int32(config.AuthMethodType),
|
AuthMethodType: int32(config.AuthMethodType),
|
||||||
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
||||||
DevMode: config.DevMode,
|
DevMode: config.DevMode,
|
||||||
|
AccessTokenType: int32(config.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: config.AccessTokenRoleAssertion,
|
||||||
|
IDTokenRoleAssertion: config.IDTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,18 +106,21 @@ func OIDCConfigToModel(config *OIDCConfig) *model.OIDCConfig {
|
|||||||
grantTypes[i] = model.OIDCGrantType(rt)
|
grantTypes[i] = model.OIDCGrantType(rt)
|
||||||
}
|
}
|
||||||
oidcConfig := &model.OIDCConfig{
|
oidcConfig := &model.OIDCConfig{
|
||||||
ObjectRoot: config.ObjectRoot,
|
ObjectRoot: config.ObjectRoot,
|
||||||
AppID: config.AppID,
|
AppID: config.AppID,
|
||||||
OIDCVersion: model.OIDCVersion(config.Version),
|
OIDCVersion: model.OIDCVersion(config.Version),
|
||||||
ClientID: config.ClientID,
|
ClientID: config.ClientID,
|
||||||
ClientSecret: config.ClientSecret,
|
ClientSecret: config.ClientSecret,
|
||||||
RedirectUris: config.RedirectUris,
|
RedirectUris: config.RedirectUris,
|
||||||
ResponseTypes: responseTypes,
|
ResponseTypes: responseTypes,
|
||||||
GrantTypes: grantTypes,
|
GrantTypes: grantTypes,
|
||||||
ApplicationType: model.OIDCApplicationType(config.ApplicationType),
|
ApplicationType: model.OIDCApplicationType(config.ApplicationType),
|
||||||
AuthMethodType: model.OIDCAuthMethodType(config.AuthMethodType),
|
AuthMethodType: model.OIDCAuthMethodType(config.AuthMethodType),
|
||||||
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
||||||
DevMode: config.DevMode,
|
DevMode: config.DevMode,
|
||||||
|
AccessTokenType: model.OIDCTokenType(config.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: config.AccessTokenRoleAssertion,
|
||||||
|
IDTokenRoleAssertion: config.IDTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
oidcConfig.FillCompliance()
|
oidcConfig.FillCompliance()
|
||||||
return oidcConfig
|
return oidcConfig
|
||||||
|
@ -2,7 +2,9 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
)
|
)
|
||||||
@ -13,12 +15,14 @@ const (
|
|||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
State int32 `json:"-"`
|
ProjectRoleAssertion bool `json:"projectRoleAssertion,omitempty"`
|
||||||
Members []*ProjectMember `json:"-"`
|
ProjectRoleCheck bool `json:"projectRoleCheck,omitempty"`
|
||||||
Roles []*ProjectRole `json:"-"`
|
State int32 `json:"-"`
|
||||||
Applications []*Application `json:"-"`
|
Members []*ProjectMember `json:"-"`
|
||||||
Grants []*ProjectGrant `json:"-"`
|
Roles []*ProjectRole `json:"-"`
|
||||||
|
Applications []*Application `json:"-"`
|
||||||
|
Grants []*ProjectGrant `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProject(projects []*Project, id string) (int, *Project) {
|
func GetProject(projects []*Project, id string) (int, *Project) {
|
||||||
@ -35,6 +39,12 @@ func (p *Project) Changes(changed *Project) map[string]interface{} {
|
|||||||
if changed.Name != "" && p.Name != changed.Name {
|
if changed.Name != "" && p.Name != changed.Name {
|
||||||
changes["name"] = changed.Name
|
changes["name"] = changed.Name
|
||||||
}
|
}
|
||||||
|
if p.ProjectRoleAssertion != changed.ProjectRoleAssertion {
|
||||||
|
changes["projectRoleAssertion"] = changed.ProjectRoleAssertion
|
||||||
|
}
|
||||||
|
if p.ProjectRoleCheck != changed.ProjectRoleCheck {
|
||||||
|
changes["projectRoleCheck"] = changed.ProjectRoleCheck
|
||||||
|
}
|
||||||
return changes
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,13 +54,15 @@ func ProjectFromModel(project *model.Project) *Project {
|
|||||||
apps := AppsFromModel(project.Applications)
|
apps := AppsFromModel(project.Applications)
|
||||||
grants := GrantsFromModel(project.Grants)
|
grants := GrantsFromModel(project.Grants)
|
||||||
return &Project{
|
return &Project{
|
||||||
ObjectRoot: project.ObjectRoot,
|
ObjectRoot: project.ObjectRoot,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
State: int32(project.State),
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
Members: members,
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
Roles: roles,
|
State: int32(project.State),
|
||||||
Applications: apps,
|
Members: members,
|
||||||
Grants: grants,
|
Roles: roles,
|
||||||
|
Applications: apps,
|
||||||
|
Grants: grants,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +72,15 @@ func ProjectToModel(project *Project) *model.Project {
|
|||||||
apps := AppsToModel(project.Applications)
|
apps := AppsToModel(project.Applications)
|
||||||
grants := GrantsToModel(project.Grants)
|
grants := GrantsToModel(project.Grants)
|
||||||
return &model.Project{
|
return &model.Project{
|
||||||
ObjectRoot: project.ObjectRoot,
|
ObjectRoot: project.ObjectRoot,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
State: model.ProjectState(project.State),
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
Members: members,
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
Roles: roles,
|
State: model.ProjectState(project.State),
|
||||||
Applications: apps,
|
Members: members,
|
||||||
Grants: grants,
|
Roles: roles,
|
||||||
|
Applications: apps,
|
||||||
|
Grants: grants,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,15 @@ func PutApplication(db *gorm.DB, table string, app *model.ApplicationView) error
|
|||||||
return save(db, app)
|
return save(db, app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PutApplications(db *gorm.DB, table string, apps ...*model.ApplicationView) error {
|
||||||
|
save := repository.PrepareBulkSave(table)
|
||||||
|
s := make([]interface{}, len(apps))
|
||||||
|
for i, app := range apps {
|
||||||
|
s[i] = app
|
||||||
|
}
|
||||||
|
return save(db, s...)
|
||||||
|
}
|
||||||
|
|
||||||
func DeleteApplication(db *gorm.DB, table, appID string) error {
|
func DeleteApplication(db *gorm.DB, table, appID string) error {
|
||||||
delete := repository.PrepareDeleteByKey(table, model.ApplicationSearchKey(proj_model.AppSearchKeyAppID), appID)
|
delete := repository.PrepareDeleteByKey(table, model.ApplicationSearchKey(proj_model.AppSearchKeyAppID), appID)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
|
@ -23,12 +23,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ApplicationView struct {
|
type ApplicationView struct {
|
||||||
ID string `json:"appId" gorm:"column:id;primary_key"`
|
ID string `json:"appId" gorm:"column:id;primary_key"`
|
||||||
ProjectID string `json:"-" gorm:"column:project_id"`
|
ProjectID string `json:"-" gorm:"column:project_id"`
|
||||||
Name string `json:"name" gorm:"column:app_name"`
|
Name string `json:"name" gorm:"column:app_name"`
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||||
State int32 `json:"-" gorm:"column:app_state"`
|
State int32 `json:"-" gorm:"column:app_state"`
|
||||||
|
ProjectRoleAssertion bool `json:"projectRoleAssertion" gorm:"column:project_role_assertion"`
|
||||||
|
ProjectRoleCheck bool `json:"projectRoleCheck" gorm:"column:project_role_check"`
|
||||||
|
|
||||||
IsOIDC bool `json:"-" gorm:"column:is_oidc"`
|
IsOIDC bool `json:"-" gorm:"column:is_oidc"`
|
||||||
OIDCVersion int32 `json:"oidcVersion" gorm:"column:oidc_version"`
|
OIDCVersion int32 `json:"oidcVersion" gorm:"column:oidc_version"`
|
||||||
@ -43,58 +45,24 @@ type ApplicationView struct {
|
|||||||
ComplianceProblems pq.StringArray `json:"-" gorm:"column:compliance_problems"`
|
ComplianceProblems pq.StringArray `json:"-" gorm:"column:compliance_problems"`
|
||||||
DevMode bool `json:"devMode" gorm:"column:dev_mode"`
|
DevMode bool `json:"devMode" gorm:"column:dev_mode"`
|
||||||
OriginAllowList pq.StringArray `json:"-" gorm:"column:origin_allow_list"`
|
OriginAllowList pq.StringArray `json:"-" gorm:"column:origin_allow_list"`
|
||||||
|
AccessTokenType int32 `json:"accessTokenType" gorm:"column:access_token_type"`
|
||||||
|
AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion" gorm:"column:access_token_role_assertion"`
|
||||||
|
IDTokenRoleAssertion bool `json:"idTokenRoleAssertion" gorm:"column:id_token_role_assertion"`
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"sequence"`
|
Sequence uint64 `json:"-" gorm:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplicationViewFromModel(app *model.ApplicationView) *ApplicationView {
|
|
||||||
return &ApplicationView{
|
|
||||||
ID: app.ID,
|
|
||||||
ProjectID: app.ProjectID,
|
|
||||||
Name: app.Name,
|
|
||||||
State: int32(app.State),
|
|
||||||
Sequence: app.Sequence,
|
|
||||||
CreationDate: app.CreationDate,
|
|
||||||
ChangeDate: app.ChangeDate,
|
|
||||||
|
|
||||||
IsOIDC: app.IsOIDC,
|
|
||||||
OIDCClientID: app.OIDCClientID,
|
|
||||||
OIDCRedirectUris: app.OIDCRedirectUris,
|
|
||||||
OIDCResponseTypes: OIDCResponseTypesFromModel(app.OIDCResponseTypes),
|
|
||||||
OIDCGrantTypes: OIDCGrantTypesFromModel(app.OIDCGrantTypes),
|
|
||||||
OIDCApplicationType: int32(app.OIDCApplicationType),
|
|
||||||
OIDCAuthMethodType: int32(app.OIDCAuthMethodType),
|
|
||||||
OIDCPostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris,
|
|
||||||
DevMode: app.DevMode,
|
|
||||||
OriginAllowList: app.OriginAllowList,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func OIDCResponseTypesFromModel(oidctypes []model.OIDCResponseType) []int64 {
|
|
||||||
result := make([]int64, len(oidctypes))
|
|
||||||
for i, t := range oidctypes {
|
|
||||||
result[i] = int64(t)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func OIDCGrantTypesFromModel(granttypes []model.OIDCGrantType) []int64 {
|
|
||||||
result := make([]int64, len(granttypes))
|
|
||||||
for i, t := range granttypes {
|
|
||||||
result[i] = int64(t)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func ApplicationViewToModel(app *ApplicationView) *model.ApplicationView {
|
func ApplicationViewToModel(app *ApplicationView) *model.ApplicationView {
|
||||||
return &model.ApplicationView{
|
return &model.ApplicationView{
|
||||||
ID: app.ID,
|
ID: app.ID,
|
||||||
ProjectID: app.ProjectID,
|
ProjectID: app.ProjectID,
|
||||||
Name: app.Name,
|
Name: app.Name,
|
||||||
State: model.AppState(app.State),
|
State: model.AppState(app.State),
|
||||||
Sequence: app.Sequence,
|
Sequence: app.Sequence,
|
||||||
CreationDate: app.CreationDate,
|
CreationDate: app.CreationDate,
|
||||||
ChangeDate: app.ChangeDate,
|
ChangeDate: app.ChangeDate,
|
||||||
|
ProjectRoleAssertion: app.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: app.ProjectRoleCheck,
|
||||||
|
|
||||||
IsOIDC: app.IsOIDC,
|
IsOIDC: app.IsOIDC,
|
||||||
OIDCVersion: model.OIDCVersion(app.OIDCVersion),
|
OIDCVersion: model.OIDCVersion(app.OIDCVersion),
|
||||||
@ -109,6 +77,9 @@ func ApplicationViewToModel(app *ApplicationView) *model.ApplicationView {
|
|||||||
ComplianceProblems: app.ComplianceProblems,
|
ComplianceProblems: app.ComplianceProblems,
|
||||||
DevMode: app.DevMode,
|
DevMode: app.DevMode,
|
||||||
OriginAllowList: app.OriginAllowList,
|
OriginAllowList: app.OriginAllowList,
|
||||||
|
AccessTokenType: model.OIDCTokenType(app.AccessTokenType),
|
||||||
|
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
|
||||||
|
IDTokenRoleAssertion: app.IDTokenRoleAssertion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +123,8 @@ func (a *ApplicationView) AppendEventIfMyApp(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
case es_model.ApplicationRemoved:
|
case es_model.ApplicationRemoved:
|
||||||
return view.SetData(event)
|
return view.SetData(event)
|
||||||
|
case es_model.ProjectChanged:
|
||||||
|
return a.AppendEvent(event)
|
||||||
case es_model.ProjectRemoved:
|
case es_model.ProjectRemoved:
|
||||||
return a.AppendEvent(event)
|
return a.AppendEvent(event)
|
||||||
default:
|
default:
|
||||||
@ -187,6 +160,8 @@ func (a *ApplicationView) AppendEvent(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
a.setCompliance()
|
a.setCompliance()
|
||||||
return a.setOriginAllowList()
|
return a.setOriginAllowList()
|
||||||
|
case es_model.ProjectChanged:
|
||||||
|
return a.SetData(event)
|
||||||
case es_model.ApplicationDeactivated:
|
case es_model.ApplicationDeactivated:
|
||||||
a.State = int32(model.AppStateInactive)
|
a.State = int32(model.AppStateInactive)
|
||||||
case es_model.ApplicationReactivated:
|
case es_model.ApplicationReactivated:
|
||||||
|
@ -2,12 +2,14 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/models"
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -17,36 +19,42 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ProjectView struct {
|
type ProjectView struct {
|
||||||
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
|
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
|
||||||
Name string `json:"name" gorm:"column:project_name"`
|
Name string `json:"name" gorm:"column:project_name"`
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||||
State int32 `json:"-" gorm:"column:project_state"`
|
State int32 `json:"-" gorm:"column:project_state"`
|
||||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
ProjectRoleAssertion bool `json:"projectRoleAssertion" gorm:"column:project_role_assertion"`
|
||||||
|
ProjectRoleCheck bool `json:"projectRoleCheck" gorm:"column:project_role_check"`
|
||||||
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectFromModel(project *model.ProjectView) *ProjectView {
|
func ProjectFromModel(project *model.ProjectView) *ProjectView {
|
||||||
return &ProjectView{
|
return &ProjectView{
|
||||||
ProjectID: project.ProjectID,
|
ProjectID: project.ProjectID,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
ChangeDate: project.ChangeDate,
|
ChangeDate: project.ChangeDate,
|
||||||
CreationDate: project.CreationDate,
|
CreationDate: project.CreationDate,
|
||||||
State: int32(project.State),
|
State: int32(project.State),
|
||||||
ResourceOwner: project.ResourceOwner,
|
ResourceOwner: project.ResourceOwner,
|
||||||
Sequence: project.Sequence,
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
|
Sequence: project.Sequence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectToModel(project *ProjectView) *model.ProjectView {
|
func ProjectToModel(project *ProjectView) *model.ProjectView {
|
||||||
return &model.ProjectView{
|
return &model.ProjectView{
|
||||||
ProjectID: project.ProjectID,
|
ProjectID: project.ProjectID,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
ChangeDate: project.ChangeDate,
|
ChangeDate: project.ChangeDate,
|
||||||
CreationDate: project.CreationDate,
|
CreationDate: project.CreationDate,
|
||||||
State: model.ProjectState(project.State),
|
State: model.ProjectState(project.State),
|
||||||
ResourceOwner: project.ResourceOwner,
|
ResourceOwner: project.ResourceOwner,
|
||||||
Sequence: project.Sequence,
|
ProjectRoleAssertion: project.ProjectRoleAssertion,
|
||||||
|
ProjectRoleCheck: project.ProjectRoleCheck,
|
||||||
|
Sequence: project.Sequence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,32 +222,32 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) *model.ExternalUser {
|
func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) *model.ExternalUser {
|
||||||
displayName := tokens.IDTokenClaims.PreferredUsername
|
displayName := tokens.IDTokenClaims.GetPreferredUsername()
|
||||||
if displayName == "" && tokens.IDTokenClaims.Email != "" {
|
if displayName == "" && tokens.IDTokenClaims.GetEmail() != "" {
|
||||||
displayName = tokens.IDTokenClaims.Email
|
displayName = tokens.IDTokenClaims.GetEmail()
|
||||||
}
|
}
|
||||||
switch idpConfig.OIDCIDPDisplayNameMapping {
|
switch idpConfig.OIDCIDPDisplayNameMapping {
|
||||||
case iam_model.OIDCMappingFieldEmail:
|
case iam_model.OIDCMappingFieldEmail:
|
||||||
if tokens.IDTokenClaims.EmailVerified && tokens.IDTokenClaims.Email != "" {
|
if tokens.IDTokenClaims.IsEmailVerified() && tokens.IDTokenClaims.GetEmail() != "" {
|
||||||
displayName = tokens.IDTokenClaims.Email
|
displayName = tokens.IDTokenClaims.GetEmail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
externalUser := &model.ExternalUser{
|
externalUser := &model.ExternalUser{
|
||||||
IDPConfigID: idpConfig.IDPConfigID,
|
IDPConfigID: idpConfig.IDPConfigID,
|
||||||
ExternalUserID: tokens.IDTokenClaims.Subject,
|
ExternalUserID: tokens.IDTokenClaims.GetSubject(),
|
||||||
PreferredUsername: tokens.IDTokenClaims.PreferredUsername,
|
PreferredUsername: tokens.IDTokenClaims.GetPreferredUsername(),
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
FirstName: tokens.IDTokenClaims.GivenName,
|
FirstName: tokens.IDTokenClaims.GetGivenName(),
|
||||||
LastName: tokens.IDTokenClaims.FamilyName,
|
LastName: tokens.IDTokenClaims.GetFamilyName(),
|
||||||
NickName: tokens.IDTokenClaims.Nickname,
|
NickName: tokens.IDTokenClaims.GetNickname(),
|
||||||
Email: tokens.IDTokenClaims.Email,
|
Email: tokens.IDTokenClaims.GetEmail(),
|
||||||
IsEmailVerified: tokens.IDTokenClaims.EmailVerified,
|
IsEmailVerified: tokens.IDTokenClaims.IsEmailVerified(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if tokens.IDTokenClaims.PhoneNumber != "" {
|
if tokens.IDTokenClaims.GetPhoneNumber() != "" {
|
||||||
externalUser.Phone = tokens.IDTokenClaims.PhoneNumber
|
externalUser.Phone = tokens.IDTokenClaims.GetPhoneNumber()
|
||||||
externalUser.IsPhoneVerified = tokens.IDTokenClaims.PhoneNumberVerified
|
externalUser.IsPhoneVerified = tokens.IDTokenClaims.IsPhoneNumberVerified()
|
||||||
}
|
}
|
||||||
return externalUser
|
return externalUser
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
"github.com/caos/oidc/pkg/rp"
|
"github.com/caos/oidc/pkg/rp"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
||||||
"github.com/caos/zitadel/internal/auth_request/model"
|
"github.com/caos/zitadel/internal/auth_request/model"
|
||||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||||
@ -10,8 +15,6 @@ import (
|
|||||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
|
func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -109,11 +112,11 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAMPolicyView, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) {
|
func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAMPolicyView, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) {
|
||||||
username := tokens.IDTokenClaims.PreferredUsername
|
username := tokens.IDTokenClaims.GetPreferredUsername()
|
||||||
switch idpConfig.OIDCUsernameMapping {
|
switch idpConfig.OIDCUsernameMapping {
|
||||||
case iam_model.OIDCMappingFieldEmail:
|
case iam_model.OIDCMappingFieldEmail:
|
||||||
if tokens.IDTokenClaims.EmailVerified && tokens.IDTokenClaims.Email != "" {
|
if tokens.IDTokenClaims.IsEmailVerified() && tokens.IDTokenClaims.GetEmail() != "" {
|
||||||
username = tokens.IDTokenClaims.Email
|
username = tokens.IDTokenClaims.GetEmail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,35 +131,35 @@ func (l *Login) mapTokenToLoginUserAndExternalIDP(orgIamPolicy *iam_model.OrgIAM
|
|||||||
UserName: username,
|
UserName: username,
|
||||||
Human: &usr_model.Human{
|
Human: &usr_model.Human{
|
||||||
Profile: &usr_model.Profile{
|
Profile: &usr_model.Profile{
|
||||||
FirstName: tokens.IDTokenClaims.GivenName,
|
FirstName: tokens.IDTokenClaims.GetGivenName(),
|
||||||
LastName: tokens.IDTokenClaims.FamilyName,
|
LastName: tokens.IDTokenClaims.GetFamilyName(),
|
||||||
PreferredLanguage: tokens.IDTokenClaims.Locale,
|
PreferredLanguage: language.Tag(tokens.IDTokenClaims.GetLocale()),
|
||||||
NickName: tokens.IDTokenClaims.Nickname,
|
NickName: tokens.IDTokenClaims.GetNickname(),
|
||||||
},
|
},
|
||||||
Email: &usr_model.Email{
|
Email: &usr_model.Email{
|
||||||
EmailAddress: tokens.IDTokenClaims.Email,
|
EmailAddress: tokens.IDTokenClaims.GetEmail(),
|
||||||
IsEmailVerified: tokens.IDTokenClaims.EmailVerified,
|
IsEmailVerified: tokens.IDTokenClaims.IsEmailVerified(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if tokens.IDTokenClaims.PhoneNumber != "" {
|
if tokens.IDTokenClaims.GetPhoneNumber() != "" {
|
||||||
user.Phone = &usr_model.Phone{
|
user.Phone = &usr_model.Phone{
|
||||||
PhoneNumber: tokens.IDTokenClaims.PhoneNumber,
|
PhoneNumber: tokens.IDTokenClaims.GetPhoneNumber(),
|
||||||
IsPhoneVerified: tokens.IDTokenClaims.PhoneNumberVerified,
|
IsPhoneVerified: tokens.IDTokenClaims.IsPhoneNumberVerified(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayName := tokens.IDTokenClaims.PreferredUsername
|
displayName := tokens.IDTokenClaims.GetPreferredUsername()
|
||||||
switch idpConfig.OIDCIDPDisplayNameMapping {
|
switch idpConfig.OIDCIDPDisplayNameMapping {
|
||||||
case iam_model.OIDCMappingFieldEmail:
|
case iam_model.OIDCMappingFieldEmail:
|
||||||
if tokens.IDTokenClaims.EmailVerified && tokens.IDTokenClaims.Email != "" {
|
if tokens.IDTokenClaims.IsEmailVerified() && tokens.IDTokenClaims.GetEmail() != "" {
|
||||||
displayName = tokens.IDTokenClaims.Email
|
displayName = tokens.IDTokenClaims.GetEmail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
externalIDP := &usr_model.ExternalIDP{
|
externalIDP := &usr_model.ExternalIDP{
|
||||||
IDPConfigID: idpConfig.IDPConfigID,
|
IDPConfigID: idpConfig.IDPConfigID,
|
||||||
UserID: tokens.IDTokenClaims.Subject,
|
UserID: tokens.IDTokenClaims.GetSubject(),
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
}
|
}
|
||||||
return user, externalIDP
|
return user, externalIDP
|
||||||
|
@ -211,6 +211,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
|
|||||||
l.renderExternalNotFoundOption(w, r, authReq, err)
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
case *model.ExternalLoginStep:
|
case *model.ExternalLoginStep:
|
||||||
l.handleExternalLoginStep(w, r, authReq, step.SelectedIDPConfigID)
|
l.handleExternalLoginStep(w, r, authReq, step.SelectedIDPConfigID)
|
||||||
|
case *model.GrantRequiredStep:
|
||||||
|
l.renderInternalError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-asb43", "Errors.User.GrantRequired"))
|
||||||
default:
|
default:
|
||||||
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible"))
|
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible"))
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,7 @@ Errors:
|
|||||||
AuthRequest:
|
AuthRequest:
|
||||||
NotFound: AuthRequest konnte nicht gefunden werden
|
NotFound: AuthRequest konnte nicht gefunden werden
|
||||||
UserAgentNotCorresponding: User Agent stimmt nicht überein
|
UserAgentNotCorresponding: User Agent stimmt nicht überein
|
||||||
|
RequestTypeNotSupported: Requesttyp wird nicht unterstürzt
|
||||||
User:
|
User:
|
||||||
NotFound: Benutzer konnte nicht gefunden werden
|
NotFound: Benutzer konnte nicht gefunden werden
|
||||||
NotMatchingUserID: User stimm nicht mit User in Auth Request überein
|
NotMatchingUserID: User stimm nicht mit User in Auth Request überein
|
||||||
@ -226,5 +227,6 @@ Errors:
|
|||||||
ExternalIDP:
|
ExternalIDP:
|
||||||
IDPTypeNotImplemented: IDP Typ ist nicht implementiert
|
IDPTypeNotImplemented: IDP Typ ist nicht implementiert
|
||||||
NotAllowed: Externer Login Provider ist nicht erlaubt
|
NotAllowed: Externer Login Provider ist nicht erlaubt
|
||||||
|
GrantRequired: Der Login an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte melde dich bei deinem Administrator.
|
||||||
|
|
||||||
optional: (optional)
|
optional: (optional)
|
||||||
|
@ -187,6 +187,7 @@ Errors:
|
|||||||
AuthRequest:
|
AuthRequest:
|
||||||
NotFound: Could not find authrequest
|
NotFound: Could not find authrequest
|
||||||
UserAgentNotCorresponding: User Agent does not correspond
|
UserAgentNotCorresponding: User Agent does not correspond
|
||||||
|
RequestTypeNotSupported: Request type is not supported
|
||||||
User:
|
User:
|
||||||
NotFound: User could not be found
|
NotFound: User could not be found
|
||||||
NotMatchingUserID: User and user in authrequest don't match
|
NotMatchingUserID: User and user in authrequest don't match
|
||||||
@ -226,6 +227,7 @@ Errors:
|
|||||||
ExternalIDP:
|
ExternalIDP:
|
||||||
IDPTypeNotImplemented: IDP Type is not implemented
|
IDPTypeNotImplemented: IDP Type is not implemented
|
||||||
NotAllowed: External Login Provider not allowed
|
NotAllowed: External Login Provider not allowed
|
||||||
|
GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator.
|
||||||
|
|
||||||
|
|
||||||
optional: (optional)
|
optional: (optional)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{template "main-top" .}}
|
{{template "main-top" .}}
|
||||||
|
|
||||||
<div>
|
<div class="head">
|
||||||
{{ .ErrType }}
|
{{ .ErrType }}
|
||||||
{{ .ErrMessage }}
|
{{ .ErrMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,7 +44,7 @@ const (
|
|||||||
type TokenSearchQuery struct {
|
type TokenSearchQuery struct {
|
||||||
Key TokenSearchKey
|
Key TokenSearchKey
|
||||||
Method model.SearchMethod
|
Method model.SearchMethod
|
||||||
Value string
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenSearchResponse struct {
|
type TokenSearchResponse struct {
|
||||||
|
@ -7,20 +7,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UserGrantView struct {
|
type UserGrantView struct {
|
||||||
ID string
|
ID string
|
||||||
ResourceOwner string
|
ResourceOwner string
|
||||||
UserID string
|
UserID string
|
||||||
ProjectID string
|
ProjectID string
|
||||||
GrantID string
|
GrantID string
|
||||||
UserName string
|
UserName string
|
||||||
FirstName string
|
FirstName string
|
||||||
LastName string
|
LastName string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
Email string
|
Email string
|
||||||
ProjectName string
|
ProjectName string
|
||||||
OrgName string
|
OrgName string
|
||||||
OrgDomain string
|
OrgPrimaryDomain string
|
||||||
RoleKeys []string
|
RoleKeys []string
|
||||||
|
|
||||||
CreationDate time.Time
|
CreationDate time.Time
|
||||||
ChangeDate time.Time
|
ChangeDate time.Time
|
||||||
|
@ -5,11 +5,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/models"
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/usergrant/model"
|
"github.com/caos/zitadel/internal/usergrant/model"
|
||||||
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||||
"github.com/lib/pq"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -24,19 +25,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UserGrantView struct {
|
type UserGrantView struct {
|
||||||
ID string `json:"-" gorm:"column:id;primary_key"`
|
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||||
ResourceOwner string `json:"-" gorm:"resource_owner"`
|
ResourceOwner string `json:"-" gorm:"resource_owner"`
|
||||||
UserID string `json:"userId" gorm:"user_id"`
|
UserID string `json:"userId" gorm:"user_id"`
|
||||||
ProjectID string `json:"projectId" gorm:"column:project_id"`
|
ProjectID string `json:"projectId" gorm:"column:project_id"`
|
||||||
GrantID string `json:"grantId" gorm:"column:grant_id"`
|
GrantID string `json:"grantId" gorm:"column:grant_id"`
|
||||||
UserName string `json:"-" gorm:"column:user_name"`
|
UserName string `json:"-" gorm:"column:user_name"`
|
||||||
FirstName string `json:"-" gorm:"column:first_name"`
|
FirstName string `json:"-" gorm:"column:first_name"`
|
||||||
LastName string `json:"-" gorm:"column:last_name"`
|
LastName string `json:"-" gorm:"column:last_name"`
|
||||||
DisplayName string `json:"-" gorm:"column:display_name"`
|
DisplayName string `json:"-" gorm:"column:display_name"`
|
||||||
Email string `json:"-" gorm:"column:email"`
|
Email string `json:"-" gorm:"column:email"`
|
||||||
ProjectName string `json:"-" gorm:"column:project_name"`
|
ProjectName string `json:"-" gorm:"column:project_name"`
|
||||||
OrgName string `json:"-" gorm:"column:org_name"`
|
OrgName string `json:"-" gorm:"column:org_name"`
|
||||||
RoleKeys pq.StringArray `json:"roleKeys" gorm:"column:role_keys"`
|
OrgPrimaryDomain string `json:"-" gorm:"column:org_primary_domain"`
|
||||||
|
RoleKeys pq.StringArray `json:"roleKeys" gorm:"column:role_keys"`
|
||||||
|
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||||
@ -47,22 +49,23 @@ type UserGrantView struct {
|
|||||||
|
|
||||||
func UserGrantToModel(grant *UserGrantView) *model.UserGrantView {
|
func UserGrantToModel(grant *UserGrantView) *model.UserGrantView {
|
||||||
return &model.UserGrantView{
|
return &model.UserGrantView{
|
||||||
ID: grant.ID,
|
ID: grant.ID,
|
||||||
ResourceOwner: grant.ResourceOwner,
|
ResourceOwner: grant.ResourceOwner,
|
||||||
UserID: grant.UserID,
|
UserID: grant.UserID,
|
||||||
ProjectID: grant.ProjectID,
|
ProjectID: grant.ProjectID,
|
||||||
ChangeDate: grant.ChangeDate,
|
ChangeDate: grant.ChangeDate,
|
||||||
CreationDate: grant.CreationDate,
|
CreationDate: grant.CreationDate,
|
||||||
State: model.UserGrantState(grant.State),
|
State: model.UserGrantState(grant.State),
|
||||||
UserName: grant.UserName,
|
UserName: grant.UserName,
|
||||||
FirstName: grant.FirstName,
|
FirstName: grant.FirstName,
|
||||||
LastName: grant.LastName,
|
LastName: grant.LastName,
|
||||||
DisplayName: grant.DisplayName,
|
DisplayName: grant.DisplayName,
|
||||||
Email: grant.Email,
|
Email: grant.Email,
|
||||||
ProjectName: grant.ProjectName,
|
ProjectName: grant.ProjectName,
|
||||||
OrgName: grant.OrgName,
|
OrgName: grant.OrgName,
|
||||||
RoleKeys: grant.RoleKeys,
|
OrgPrimaryDomain: grant.OrgPrimaryDomain,
|
||||||
Sequence: grant.Sequence,
|
RoleKeys: grant.RoleKeys,
|
||||||
|
Sequence: grant.Sequence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
migrations/cockroach/V1.18__scope_projectroles.sql
Normal file
40
migrations/cockroach/V1.18__scope_projectroles.sql
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
CREATE TABLE auth.project_roles (
|
||||||
|
project_id TEXT,
|
||||||
|
role_key TEXT,
|
||||||
|
display_name TEXT,
|
||||||
|
resource_owner TEXT,
|
||||||
|
org_id TEXT,
|
||||||
|
group_name TEXT,
|
||||||
|
|
||||||
|
creation_date TIMESTAMPTZ,
|
||||||
|
sequence BIGINT,
|
||||||
|
|
||||||
|
PRIMARY KEY (org_id, project_id, role_key)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE authz.user_grants ADD COLUMN org_primary_domain TEXT;
|
||||||
|
ALTER TABLE auth.user_grants ADD COLUMN org_primary_domain TEXT;
|
||||||
|
ALTER TABLE management.user_grants ADD COLUMN org_primary_domain TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE authz.applications ADD COLUMN access_token_type SMALLINT;
|
||||||
|
ALTER TABLE auth.applications ADD COLUMN access_token_type SMALLINT;
|
||||||
|
ALTER TABLE management.applications ADD COLUMN access_token_type SMALLINT;
|
||||||
|
|
||||||
|
ALTER TABLE management.projects ADD COLUMN project_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE management.projects ADD COLUMN project_role_check BOOLEAN;
|
||||||
|
|
||||||
|
ALTER TABLE authz.applications ADD COLUMN project_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE auth.applications ADD COLUMN project_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE management.applications ADD COLUMN project_role_assertion BOOLEAN;
|
||||||
|
|
||||||
|
ALTER TABLE authz.applications ADD COLUMN project_role_check BOOLEAN;
|
||||||
|
ALTER TABLE auth.applications ADD COLUMN project_role_check BOOLEAN;
|
||||||
|
ALTER TABLE management.applications ADD COLUMN project_role_check BOOLEAN;
|
||||||
|
|
||||||
|
ALTER TABLE authz.applications ADD COLUMN access_token_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE auth.applications ADD COLUMN access_token_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE management.applications ADD COLUMN access_token_role_assertion BOOLEAN;
|
||||||
|
|
||||||
|
ALTER TABLE authz.applications ADD COLUMN id_token_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE auth.applications ADD COLUMN id_token_role_assertion BOOLEAN;
|
||||||
|
ALTER TABLE management.applications ADD COLUMN id_token_role_assertion BOOLEAN;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6381,6 +6381,10 @@ func (m *ProjectCreateRequest) Validate() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleCheck
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6462,6 +6466,10 @@ func (m *ProjectUpdateRequest) Validate() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleCheck
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6659,6 +6667,10 @@ func (m *ProjectView) Validate() error {
|
|||||||
|
|
||||||
// no validation rules for Sequence
|
// no validation rules for Sequence
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleCheck
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6998,6 +7010,10 @@ func (m *Project) Validate() error {
|
|||||||
|
|
||||||
// no validation rules for Sequence
|
// no validation rules for Sequence
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for ProjectRoleCheck
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8850,6 +8866,12 @@ func (m *OIDCConfig) Validate() error {
|
|||||||
|
|
||||||
// no validation rules for DevMode
|
// no validation rules for DevMode
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenType
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for IdTokenRoleAssertion
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8937,6 +8959,12 @@ func (m *OIDCApplicationCreate) Validate() error {
|
|||||||
|
|
||||||
// no validation rules for DevMode
|
// no validation rules for DevMode
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenType
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for IdTokenRoleAssertion
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9024,6 +9052,12 @@ func (m *OIDCConfigUpdate) Validate() error {
|
|||||||
|
|
||||||
// no validation rules for DevMode
|
// no validation rules for DevMode
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenType
|
||||||
|
|
||||||
|
// no validation rules for AccessTokenRoleAssertion
|
||||||
|
|
||||||
|
// no validation rules for IdTokenRoleAssertion
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2180,11 +2180,15 @@ enum OrgMemberSearchKey {
|
|||||||
|
|
||||||
message ProjectCreateRequest {
|
message ProjectCreateRequest {
|
||||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
bool project_role_assertion = 2;
|
||||||
|
bool project_role_check = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProjectUpdateRequest {
|
message ProjectUpdateRequest {
|
||||||
string id = 1 [(validate.rules).string = {min_len: 1}];
|
string id = 1 [(validate.rules).string = {min_len: 1}];
|
||||||
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
bool project_role_assertion = 3;
|
||||||
|
bool project_role_check = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProjectSearchResponse {
|
message ProjectSearchResponse {
|
||||||
@ -2204,6 +2208,8 @@ message ProjectView {
|
|||||||
google.protobuf.Timestamp creation_date = 5;
|
google.protobuf.Timestamp creation_date = 5;
|
||||||
string resource_owner = 6;
|
string resource_owner = 6;
|
||||||
uint64 sequence = 7;
|
uint64 sequence = 7;
|
||||||
|
bool project_role_assertion = 8;
|
||||||
|
bool project_role_check = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProjectSearchRequest {
|
message ProjectSearchRequest {
|
||||||
@ -2234,6 +2240,8 @@ message Project {
|
|||||||
google.protobuf.Timestamp change_date = 4;
|
google.protobuf.Timestamp change_date = 4;
|
||||||
google.protobuf.Timestamp creation_date = 5;
|
google.protobuf.Timestamp creation_date = 5;
|
||||||
uint64 sequence = 6;
|
uint64 sequence = 6;
|
||||||
|
bool project_role_assertion = 7;
|
||||||
|
bool project_role_check = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProjectState {
|
enum ProjectState {
|
||||||
@ -2423,6 +2431,9 @@ message OIDCConfig {
|
|||||||
bool none_compliant = 10;
|
bool none_compliant = 10;
|
||||||
repeated caos.zitadel.api.v1.LocalizedMessage compliance_problems = 11;
|
repeated caos.zitadel.api.v1.LocalizedMessage compliance_problems = 11;
|
||||||
bool dev_mode = 12;
|
bool dev_mode = 12;
|
||||||
|
OIDCTokenType access_token_type = 13;
|
||||||
|
bool access_token_role_assertion = 14;
|
||||||
|
bool id_token_role_assertion = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OIDCApplicationCreate {
|
message OIDCApplicationCreate {
|
||||||
@ -2436,12 +2447,20 @@ message OIDCApplicationCreate {
|
|||||||
repeated string post_logout_redirect_uris = 8;
|
repeated string post_logout_redirect_uris = 8;
|
||||||
OIDCVersion version = 9;
|
OIDCVersion version = 9;
|
||||||
bool dev_mode = 10;
|
bool dev_mode = 10;
|
||||||
|
OIDCTokenType access_token_type = 11;
|
||||||
|
bool access_token_role_assertion = 12;
|
||||||
|
bool id_token_role_assertion = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OIDCVersion {
|
enum OIDCVersion {
|
||||||
OIDCV1_0 = 0;
|
OIDCV1_0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum OIDCTokenType {
|
||||||
|
OIDCTokenType_Bearer = 0;
|
||||||
|
OIDCTokenType_JWT = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message OIDCConfigUpdate {
|
message OIDCConfigUpdate {
|
||||||
string project_id = 1 [(validate.rules).string = {min_len: 1}];
|
string project_id = 1 [(validate.rules).string = {min_len: 1}];
|
||||||
string application_id = 2 [(validate.rules).string = {min_len: 1}];
|
string application_id = 2 [(validate.rules).string = {min_len: 1}];
|
||||||
@ -2452,6 +2471,9 @@ message OIDCConfigUpdate {
|
|||||||
OIDCAuthMethodType auth_method_type = 7;
|
OIDCAuthMethodType auth_method_type = 7;
|
||||||
repeated string post_logout_redirect_uris = 8;
|
repeated string post_logout_redirect_uris = 8;
|
||||||
bool dev_mode = 9;
|
bool dev_mode = 9;
|
||||||
|
OIDCTokenType access_token_type = 10;
|
||||||
|
bool access_token_role_assertion = 11;
|
||||||
|
bool id_token_role_assertion = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OIDCResponseType {
|
enum OIDCResponseType {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user