diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3362ac23bc..ce3ceccca9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,7 +91,7 @@ jobs: pull-requests: write needs: [version, core-unit-test, core-integration-test, lint, container, e2e] - if: ${{ needs.version.outputs.published == 'true' && github.event_name == 'workflow_dispatch' }} + if: ${{ github.event_name == 'workflow_dispatch' }} secrets: GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }} with: diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index abf5f44807..c5a9a4008f 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -47,4 +47,4 @@ jobs: name: output id: output run: - if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=" >> "$GITHUB_OUTPUT";fi + if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=${{ github.sha }}" >> "$GITHUB_OUTPUT";fi diff --git a/.gitignore b/.gitignore index 8b8a107f07..fe02b30b6c 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ migrations/cockroach/migrate_cloud.go !/.artifacts/zitadel /zitadel node_modules/ +.kreya go.work go.work.sum diff --git a/cmd/setup/19.go b/cmd/setup/19.go new file mode 100644 index 0000000000..7919ef9ad9 --- /dev/null +++ b/cmd/setup/19.go @@ -0,0 +1,26 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" +) + +var ( + //go:embed 19.sql + addCurrentSequencesIndex string +) + +type AddCurrentSequencesIndex struct { + dbClient *database.DB +} + +func (mig *AddCurrentSequencesIndex) Execute(ctx context.Context) error { + _, err := mig.dbClient.ExecContext(ctx, addCurrentSequencesIndex) + return err +} + +func (mig *AddCurrentSequencesIndex) String() string { + return "19_add_current_sequences_index" +} diff --git a/cmd/setup/19.sql b/cmd/setup/19.sql new file mode 100644 index 0000000000..0d690c9552 --- /dev/null +++ b/cmd/setup/19.sql @@ -0,0 +1 @@ +CREATE INDEX CONCURRENTLY IF NOT EXISTS events2_current_sequence ON eventstore.events2 ("sequence" DESC, aggregate_id, aggregate_type, instance_id); \ No newline at end of file diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 92ca30c3b1..84e7903dcf 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -76,6 +76,7 @@ type Steps struct { s16UniqueConstraintsLower *UniqueConstraintToLower s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames + s19AddCurrentStatesIndex *AddCurrentSequencesIndex } type encryptionKeyConfig struct { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 476068fea3..4fc3f64481 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -109,6 +109,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s16UniqueConstraintsLower = &UniqueConstraintToLower{dbClient: queryDBClient} steps.s17AddOffsetToUniqueConstraints = &AddOffsetToCurrentStates{dbClient: queryDBClient} steps.s18AddLowerFieldsToLoginNames = &AddLowerFieldsToLoginNames{dbClient: queryDBClient} + steps.s19AddCurrentStatesIndex = &AddCurrentSequencesIndex{dbClient: queryDBClient} err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -153,6 +154,8 @@ func Setup(config *Config, steps *Steps, masterKey string) { logging.WithFields("name", steps.s16UniqueConstraintsLower.String()).OnError(err).Fatal("migration failed") err = migration.Migrate(ctx, eventstoreClient, steps.s17AddOffsetToUniqueConstraints) logging.WithFields("name", steps.s17AddOffsetToUniqueConstraints.String()).OnError(err).Fatal("migration failed") + err = migration.Migrate(ctx, eventstoreClient, steps.s19AddCurrentStatesIndex) + logging.WithFields("name", steps.s19AddCurrentStatesIndex.String()).OnError(err).Fatal("migration failed") for _, repeatableStep := range repeatableSteps { err = migration.Migrate(ctx, eventstoreClient, repeatableStep) diff --git a/docs/docs/examples/introduction.mdx b/docs/docs/examples/introduction.mdx index 4ee14d51b9..49ac1a834d 100644 --- a/docs/docs/examples/introduction.mdx +++ b/docs/docs/examples/introduction.mdx @@ -1,5 +1,5 @@ --- -title: Overview of ZITADEL Examples, Quickstarts, and SDKs +title: Overview of ZITADEL example applications and quickstarts sidebar_label: Overview --- @@ -198,3 +198,12 @@ Our examples cover a range of programming languages and frameworks, so no matter + +## Other example applications + +- [B2B customer portal](https://github.com/zitadel/zitadel-nextjs-b2b): Showcase the use of personal access tokens in a B2B environment. Uses NextJS Framework. +- [Frontend with backend API](https://github.com/zitadel/example-quote-generator-app): A simple web application using a React front-end and a Python back-end API, both secured using ZITADEL +- [Introspection](https://github.com/zitadel/examples-api-access-and-token-introspection): Python examples for securing an API and invoking it as a service user +- [Fine-grained authorization](https://github.com/zitadel/example-fine-grained-authorization): Leverage actions, custom metadata, and claims for attribute-based access control + +Search for the "example" tag in our repository to [explore all examples](https://github.com/search?q=topic%3Aexamples+org%3Azitadel&type=repositories). diff --git a/go.mod b/go.mod index d316c9ebcd..6b1bf71d41 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,7 @@ require ( github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 github.com/ttacon/libphonenumber v1.2.1 github.com/zitadel/logging v0.5.0 - github.com/zitadel/oidc/v3 v3.8.0 + github.com/zitadel/oidc/v3 v3.8.1 github.com/zitadel/passwap v0.4.0 github.com/zitadel/saml v0.1.3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 @@ -74,7 +74,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.20.0 go.opentelemetry.io/otel/trace v1.21.0 go.uber.org/mock v0.3.0 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 golang.org/x/net v0.19.0 golang.org/x/oauth2 v0.15.0 @@ -90,7 +90,7 @@ require ( require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.44.0 // indirect github.com/crewjam/httperr v0.2.0 // indirect - github.com/go-chi/chi/v5 v5.0.10 // indirect + github.com/go-chi/chi/v5 v5.0.11 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect diff --git a/go.sum b/go.sum index c7da6b8f96..9954053ade 100644 --- a/go.sum +++ b/go.sum @@ -258,8 +258,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= +github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= @@ -867,8 +867,8 @@ github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zitadel/logging v0.5.0 h1:Kunouvqse/efXy4UDvFw5s3vP+Z4AlHo3y8wF7stXHA= github.com/zitadel/logging v0.5.0/go.mod h1:IzP5fzwFhzzyxHkSmfF8dsyqFsQRJLLcQmwhIBzlGsE= -github.com/zitadel/oidc/v3 v3.8.0 h1:4Nvok+e6o3FDpqrf14JOg4EVBvwXNFOI1lFHPZU75iA= -github.com/zitadel/oidc/v3 v3.8.0/go.mod h1:v+aHyg4lBAUuuUHINwXqHtKunPJZo8kPvMpRRBYEKHY= +github.com/zitadel/oidc/v3 v3.8.1 h1:YsFWUpT3JFsDlF9ePwM851CymDwqfQ3UU1CoOEOMEdU= +github.com/zitadel/oidc/v3 v3.8.1/go.mod h1:rUKTJBsamKtqurN1MpuRYxF5FgW/9RJ/1/AF3g7/2k0= github.com/zitadel/passwap v0.4.0 h1:cMaISx+Ve7ilgG7Q8xOli4Z6IWr8Gndss+jeBk5A3O0= github.com/zitadel/passwap v0.4.0/go.mod h1:yHaDM4A68yRkdic5BZ4iUNoc19hT+kYt8n1/Nz+I87g= github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM= @@ -953,8 +953,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index 6b90a940ef..251b08c1b1 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -10,7 +10,6 @@ import ( "github.com/zitadel/zitadel/internal/api/grpc/org" user_grpc "github.com/zitadel/zitadel/internal/api/grpc/user" "github.com/zitadel/zitadel/internal/command" - "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/query" @@ -275,41 +274,6 @@ func ListMyProjectOrgsRequestToQuery(req *auth_pb.ListMyProjectOrgsRequest) (*qu }, nil } -func membershipToDomain(memberships []*query.Membership) []*domain.UserMembership { - result := make([]*domain.UserMembership, len(memberships)) - for i, membership := range memberships { - typ, displayName, aggID, objID := MemberTypeToDomain(membership) - result[i] = &domain.UserMembership{ - UserID: membership.UserID, - MemberType: typ, - AggregateID: aggID, - ObjectID: objID, - Roles: membership.Roles, - DisplayName: displayName, - CreationDate: membership.CreationDate, - ChangeDate: membership.ChangeDate, - ResourceOwner: membership.ResourceOwner, - //TODO: implement - // ResourceOwnerName: membership.ResourceOwnerName, - Sequence: membership.Sequence, - } - } - return result -} - -func MemberTypeToDomain(m *query.Membership) (_ domain.MemberType, displayName, aggID, objID string) { - if m.Org != nil { - return domain.MemberTypeOrganisation, m.Org.Name, m.Org.OrgID, "" - } else if m.IAM != nil { - return domain.MemberTypeIam, m.IAM.Name, m.IAM.IAMID, "" - } else if m.Project != nil { - return domain.MemberTypeProject, m.Project.Name, m.Project.ProjectID, "" - } else if m.ProjectGrant != nil { - return domain.MemberTypeProjectGrant, m.ProjectGrant.ProjectName, m.ProjectGrant.ProjectID, m.ProjectGrant.GrantID - } - return domain.MemberTypeUnspecified, "", "", "" -} - func cascadingMemberships(memberships []*query.Membership) []*command.CascadingMembership { cascades := make([]*command.CascadingMembership, len(memberships)) for i, membership := range memberships { diff --git a/internal/api/grpc/idp/converter.go b/internal/api/grpc/idp/converter.go index 6cf44a834e..c92f2bd3b0 100644 --- a/internal/api/grpc/idp/converter.go +++ b/internal/api/grpc/idp/converter.go @@ -6,7 +6,6 @@ import ( obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object" "github.com/zitadel/zitadel/internal/domain" - iam_model "github.com/zitadel/zitadel/internal/iam/model" "github.com/zitadel/zitadel/internal/idp/providers/azuread" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/repository/idp" @@ -255,40 +254,6 @@ func IDPProviderTypeFromPb(typ idp_pb.IDPOwnerType) domain.IdentityProviderType } } -func IDPProviderTypeModelFromPb(typ idp_pb.IDPOwnerType) iam_model.IDPProviderType { - switch typ { - case idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG: - return iam_model.IDPProviderTypeOrg - case idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM: - return iam_model.IDPProviderTypeSystem - default: - return iam_model.IDPProviderTypeOrg - } -} - -func IDPIDQueryToModel(query *idp_pb.IDPIDQuery) *iam_model.IDPConfigSearchQuery { - return &iam_model.IDPConfigSearchQuery{ - Key: iam_model.IDPConfigSearchKeyIdpConfigID, - Method: domain.SearchMethodEquals, - Value: query.Id, - } -} - -func IDPNameQueryToModel(query *idp_pb.IDPNameQuery) *iam_model.IDPConfigSearchQuery { - return &iam_model.IDPConfigSearchQuery{ - Key: iam_model.IDPConfigSearchKeyName, - Method: obj_grpc.TextMethodToModel(query.Method), - Value: query.Name, - } -} - -func IDPOwnerTypeQueryToModel(query *idp_pb.IDPOwnerTypeQuery) *iam_model.IDPConfigSearchQuery { - return &iam_model.IDPConfigSearchQuery{ - Key: iam_model.IDPConfigSearchKeyIdpProviderType, - Method: domain.SearchMethodEquals, - Value: IDPProviderTypeModelFromPb(query.OwnerType), - } -} func ownerTypeToPB(typ domain.IdentityProviderType) idp_pb.IDPOwnerType { switch typ { case domain.IdentityProviderTypeOrg: diff --git a/internal/api/grpc/management/idp_converter.go b/internal/api/grpc/management/idp_converter.go index d86fe478d1..d8949a5444 100644 --- a/internal/api/grpc/management/idp_converter.go +++ b/internal/api/grpc/management/idp_converter.go @@ -11,7 +11,6 @@ import ( "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore/v1/models" - iam_model "github.com/zitadel/zitadel/internal/iam/model" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/zerrors" idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp" @@ -136,29 +135,6 @@ func idpQueryToModel(idpQuery *mgmt_pb.IDPQuery) (query.SearchQuery, error) { } } -func idpProviderViewsToDomain(idps []*iam_model.IDPProviderView) []*domain.IDPProvider { - idpProvider := make([]*domain.IDPProvider, len(idps)) - for i, idp := range idps { - idpProvider[i] = &domain.IDPProvider{ - ObjectRoot: models.ObjectRoot{ - AggregateID: idp.AggregateID, - }, - IDPConfigID: idp.IDPConfigID, - Type: idpConfigTypeToDomain(idp.IDPProviderType), - } - } - return idpProvider -} - -func idpConfigTypeToDomain(idpType iam_model.IDPProviderType) domain.IdentityProviderType { - switch idpType { - case iam_model.IDPProviderTypeOrg: - return domain.IdentityProviderTypeOrg - default: - return domain.IdentityProviderTypeSystem - } -} - func userLinksToDomain(idps []*query.IDPUserLink) []*domain.UserIDPLink { links := make([]*domain.UserIDPLink, len(idps)) for i, idp := range idps { diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go index d20ad57c4b..dc627c885a 100644 --- a/internal/api/grpc/management/user_converter.go +++ b/internal/api/grpc/management/user_converter.go @@ -18,7 +18,6 @@ import ( "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/query" - user_model "github.com/zitadel/zitadel/internal/user/model" mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management" ) @@ -359,38 +358,3 @@ func ListUserMembershipsRequestToModel(ctx context.Context, req *mgmt_pb.ListUse Queries: queries, }, nil } - -func UserMembershipViewsToDomain(memberships []*user_model.UserMembershipView) []*domain.UserMembership { - result := make([]*domain.UserMembership, len(memberships)) - for i, membership := range memberships { - result[i] = &domain.UserMembership{ - UserID: membership.UserID, - MemberType: MemberTypeToDomain(membership.MemberType), - AggregateID: membership.AggregateID, - ObjectID: membership.ObjectID, - Roles: membership.Roles, - DisplayName: membership.DisplayName, - CreationDate: membership.CreationDate, - ChangeDate: membership.ChangeDate, - ResourceOwner: membership.ResourceOwner, - ResourceOwnerName: membership.ResourceOwnerName, - Sequence: membership.Sequence, - } - } - return result -} - -func MemberTypeToDomain(mType user_model.MemberType) domain.MemberType { - switch mType { - case user_model.MemberTypeIam: - return domain.MemberTypeIam - case user_model.MemberTypeOrganisation: - return domain.MemberTypeOrganisation - case user_model.MemberTypeProject: - return domain.MemberTypeProject - case user_model.MemberTypeProjectGrant: - return domain.MemberTypeProjectGrant - default: - return domain.MemberTypeUnspecified - } -} diff --git a/internal/api/grpc/member/converter.go b/internal/api/grpc/member/converter.go index 0d0497d31c..0e5c87ceb1 100644 --- a/internal/api/grpc/member/converter.go +++ b/internal/api/grpc/member/converter.go @@ -9,13 +9,6 @@ import ( member_pb "github.com/zitadel/zitadel/pkg/grpc/member" ) -func MemberToDomain(member *member_pb.Member) *domain.Member { - return &domain.Member{ - UserID: member.UserId, - Roles: member.Roles, - } -} - func MembersToPb(assetAPIPrefix string, members []*query.Member) []*member_pb.Member { m := make([]*member_pb.Member, len(members)) for i, member := range members { diff --git a/internal/api/grpc/object/converter.go b/internal/api/grpc/object/converter.go index 85fdf5fba0..bdb7a1362d 100644 --- a/internal/api/grpc/object/converter.go +++ b/internal/api/grpc/object/converter.go @@ -97,29 +97,6 @@ func ToListDetails( return details } -func TextMethodToModel(method object_pb.TextQueryMethod) domain.SearchMethod { - switch method { - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS: - return domain.SearchMethodEquals - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE: - return domain.SearchMethodEqualsIgnoreCase - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH: - return domain.SearchMethodStartsWith - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE: - return domain.SearchMethodStartsWithIgnoreCase - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS: - return domain.SearchMethodContains - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE: - return domain.SearchMethodContainsIgnoreCase - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH: - return domain.SearchMethodEndsWith - case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE: - return domain.SearchMethodEndsWithIgnoreCase - default: - return -1 - } -} - func TextMethodToQuery(method object_pb.TextQueryMethod) query.TextComparison { switch method { case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS: diff --git a/internal/api/grpc/oidc/v2/oidc_integration_test.go b/internal/api/grpc/oidc/v2/oidc_integration_test.go index db11f9022b..f3e7e0a75d 100644 --- a/internal/api/grpc/oidc/v2/oidc_integration_test.go +++ b/internal/api/grpc/oidc/v2/oidc_integration_test.go @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { func TestServer_GetAuthRequest(t *testing.T) { project, err := Tester.CreateProject(CTX) require.NoError(t, err) - client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) require.NoError(t, err) authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) require.NoError(t, err) @@ -96,7 +96,7 @@ func TestServer_GetAuthRequest(t *testing.T) { func TestServer_CreateCallback(t *testing.T) { project, err := Tester.CreateProject(CTX) require.NoError(t, err) - client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) require.NoError(t, err) sessionResp, err := Tester.Client.SessionV2.CreateSession(CTX, &session.CreateSessionRequest{ Checks: &session.Checks{ diff --git a/internal/api/grpc/project/converter.go b/internal/api/grpc/project/converter.go index 887b82208b..d1d1fc2187 100644 --- a/internal/api/grpc/project/converter.go +++ b/internal/api/grpc/project/converter.go @@ -3,7 +3,6 @@ package project import ( "github.com/zitadel/zitadel/internal/api/grpc/object" "github.com/zitadel/zitadel/internal/domain" - proj_model "github.com/zitadel/zitadel/internal/project/model" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/zerrors" proj_pb "github.com/zitadel/zitadel/pkg/grpc/project" @@ -112,45 +111,6 @@ func privateLabelingSettingToPb(setting domain.PrivateLabelingSetting) proj_pb.P } } -func grantedProjectStateToPb(state proj_model.ProjectState) proj_pb.ProjectGrantState { - switch state { - case proj_model.ProjectStateActive: - return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_ACTIVE - case proj_model.ProjectStateInactive: - return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_INACTIVE - default: - return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_UNSPECIFIED - } -} - -func GrantedProjectQueriesToModel(queries []*proj_pb.ProjectQuery) (_ []*proj_model.ProjectGrantViewSearchQuery, err error) { - q := make([]*proj_model.ProjectGrantViewSearchQuery, len(queries)) - for i, query := range queries { - q[i], err = GrantedProjectQueryToModel(query) - if err != nil { - return nil, err - } - } - return q, nil -} - -func GrantedProjectQueryToModel(query *proj_pb.ProjectQuery) (*proj_model.ProjectGrantViewSearchQuery, error) { - switch q := query.Query.(type) { - case *proj_pb.ProjectQuery_NameQuery: - return GrantedProjectQueryNameToModel(q.NameQuery), nil - default: - return nil, zerrors.ThrowInvalidArgument(nil, "ORG-Ags42", "List.Query.Invalid") - } -} - -func GrantedProjectQueryNameToModel(query *proj_pb.ProjectNameQuery) *proj_model.ProjectGrantViewSearchQuery { - return &proj_model.ProjectGrantViewSearchQuery{ - Key: proj_model.GrantedProjectSearchKeyName, - Method: object.TextMethodToModel(query.Method), - Value: query.Name, - } -} - func RoleQueriesToModel(queries []*proj_pb.RoleQuery) (_ []query.SearchQuery, err error) { q := make([]query.SearchQuery, len(queries)) for i, query := range queries { diff --git a/internal/api/oidc/client_converter.go b/internal/api/oidc/client_converter.go index e6085926ae..b8334b578e 100644 --- a/internal/api/oidc/client_converter.go +++ b/internal/api/oidc/client_converter.go @@ -136,6 +136,20 @@ func (c *Client) IDTokenUserinfoClaimsAssertion() bool { return c.client.IDTokenUserinfoAssertion } +func (c *Client) RedirectURIGlobs() []string { + if c.DevMode() { + return c.RedirectURIs() + } + return nil +} + +func (c *Client) PostLogoutRedirectURIGlobs() []string { + if c.DevMode() { + return c.PostLogoutRedirectURIs() + } + return nil +} + func accessTokenTypeToOIDC(tokenType domain.OIDCTokenType) op.AccessTokenType { switch tokenType { case domain.OIDCTokenTypeBearer: diff --git a/internal/api/oidc/client_integration_test.go b/internal/api/oidc/client_integration_test.go index cd31607b3d..a20e388dca 100644 --- a/internal/api/oidc/client_integration_test.go +++ b/internal/api/oidc/client_integration_test.go @@ -59,48 +59,118 @@ func TestOPStorage_SetUserinfoFromToken(t *testing.T) { func TestServer_Introspect(t *testing.T) { project, err := Tester.CreateProject(CTX) require.NoError(t, err) - app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) - require.NoError(t, err) - api, err := Tester.CreateAPIClient(CTX, project.GetId()) - require.NoError(t, err) - keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{ - ProjectId: project.GetId(), - AppId: api.GetAppId(), - Type: authn.KeyType_KEY_TYPE_JSON, - ExpirationDate: nil, - }) - require.NoError(t, err) - resourceServer, err := Tester.CreateResourceServer(CTX, keyResp.GetKeyDetails()) + app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) require.NoError(t, err) - scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess, oidc_api.ScopeResourceOwner} - authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...) - sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) - linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ - AuthRequestId: authRequestID, - CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ - Session: &oidc_pb.Session{ - SessionId: sessionID, - SessionToken: sessionToken, + wantAudience := []string{app.GetClientId(), project.GetId()} + + tests := []struct { + name string + api func(*testing.T) (apiID string, resourceServer rs.ResourceServer) + wantErr bool + }{ + { + name: "client assertion", + api: func(t *testing.T) (string, rs.ResourceServer) { + api, err := Tester.CreateAPIClientJWT(CTX, project.GetId()) + require.NoError(t, err) + keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{ + ProjectId: project.GetId(), + AppId: api.GetAppId(), + Type: authn.KeyType_KEY_TYPE_JSON, + ExpirationDate: nil, + }) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServerJWTProfile(CTX, keyResp.GetKeyDetails()) + require.NoError(t, err) + return api.GetClientId(), resourceServer }, }, - }) - require.NoError(t, err) + { + name: "client credentials", + api: func(t *testing.T) (string, rs.ResourceServer) { + api, err := Tester.CreateAPIClientBasic(CTX, project.GetId()) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), api.GetClientSecret()) + require.NoError(t, err) + return api.GetClientId(), resourceServer + }, + }, + { + name: "client invalid id, error", + api: func(t *testing.T) (string, rs.ResourceServer) { + api, err := Tester.CreateAPIClientBasic(CTX, project.GetId()) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, "xxxxx", api.GetClientSecret()) + require.NoError(t, err) + return api.GetClientId(), resourceServer + }, + wantErr: true, + }, + { + name: "client invalid secret, error", + api: func(t *testing.T) (string, rs.ResourceServer) { + api, err := Tester.CreateAPIClientBasic(CTX, project.GetId()) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), "xxxxx") + require.NoError(t, err) + return api.GetClientId(), resourceServer + }, + wantErr: true, + }, + { + name: "client credentials on jwt client, error", + api: func(t *testing.T) (string, rs.ResourceServer) { + api, err := Tester.CreateAPIClientJWT(CTX, project.GetId()) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), "xxxxx") + require.NoError(t, err) + return api.GetClientId(), resourceServer + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + apiID, resourceServer := tt.api(t) + // wantAudience grows for every API we add to the project. + wantAudience = append(wantAudience, apiID) - // code exchange - code := assertCodeResponse(t, linkResp.GetCallbackUrl()) - tokens, err := exchangeTokens(t, app.GetClientId(), code) - require.NoError(t, err) - assertTokens(t, tokens, true) - assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess, oidc_api.ScopeResourceOwner} + authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) - // test actual introspection - introspection, err := rs.Introspect[*oidc.IntrospectionResponse](context.Background(), resourceServer, tokens.AccessToken) - require.NoError(t, err) - assertIntrospection(t, introspection, - Tester.OIDCIssuer(), app.GetClientId(), - scope, []string{app.GetClientId(), api.GetClientId(), project.GetId()}, - tokens.Expiry, tokens.Expiry.Add(-12*time.Hour)) + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, app.GetClientId(), code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // test actual introspection + introspection, err := rs.Introspect[*oidc.IntrospectionResponse](context.Background(), resourceServer, tokens.AccessToken) + if tt.wantErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + assertIntrospection(t, introspection, + Tester.OIDCIssuer(), app.GetClientId(), + scope, wantAudience, + tokens.Expiry, tokens.Expiry.Add(-12*time.Hour)) + }) + } } func assertUserinfo(t *testing.T, userinfo *oidc.UserInfo) { @@ -158,7 +228,7 @@ func TestServer_VerifyClient(t *testing.T) { inactiveClient, err := Tester.CreateOIDCInactivateClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) require.NoError(t, err) - nativeClient, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + nativeClient, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) require.NoError(t, err) basicWebClient, err := Tester.CreateOIDCWebClientBasic(CTX, redirectURI, logoutRedirectURI, project.GetId()) require.NoError(t, err) diff --git a/internal/api/oidc/introspect.go b/internal/api/oidc/introspect.go index 90cda8de7a..8c73755199 100644 --- a/internal/api/oidc/introspect.go +++ b/internal/api/oidc/introspect.go @@ -72,7 +72,7 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR return nil, err } - // remaining errors shoudn't be returned to the client, + // remaining errors shouldn't be returned to the client, // so we catch errors here, log them and return the response // with active: false defer func() { @@ -122,6 +122,8 @@ type introspectionClientResult struct { err error } +var errNoClientSecret = errors.New("client has no configured secret") + func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCredentials, rc chan<- *introspectionClientResult) { ctx, span := tracing.NewSpan(ctx) @@ -136,13 +138,16 @@ func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCrede if _, err := op.VerifyJWTAssertion(ctx, cc.ClientAssertion, verifier); err != nil { return "", "", oidc.ErrUnauthorizedClient().WithParent(err) } - } else { + return client.ClientID, client.ProjectID, nil + + } + if client.ClientSecret != nil { if err := crypto.CompareHash(client.ClientSecret, []byte(cc.ClientSecret), s.hashAlg); err != nil { return "", "", oidc.ErrUnauthorizedClient().WithParent(err) } + return client.ClientID, client.ProjectID, nil } - - return client.ClientID, client.ProjectID, nil + return "", "", oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret) }() span.EndWithError(err) diff --git a/internal/api/oidc/oidc_integration_test.go b/internal/api/oidc/oidc_integration_test.go index 0e4b6e9c9d..f956b5c48f 100644 --- a/internal/api/oidc/oidc_integration_test.go +++ b/internal/api/oidc/oidc_integration_test.go @@ -174,6 +174,40 @@ func Test_ZITADEL_API_success(t *testing.T) { require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId()) } +func Test_ZITADEL_API_glob_redirects(t *testing.T) { + const redirectURI = "https://my-org-1yfnjl2xj-my-app.vercel.app/api/auth/callback/zitadel" + clientID := createClientWithOpts(t, clientOpts{ + redirectURI: "https://my-org-*-my-app.vercel.app/api/auth/callback/zitadel", + logoutURI: "https://my-org-*-my-app.vercel.app/", + devMode: true, + }) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.NoError(t, err) + require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId()) +} + func Test_ZITADEL_API_inactive_access_token(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) @@ -257,9 +291,23 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) { } func createClient(t testing.TB) string { + return createClientWithOpts(t, clientOpts{ + redirectURI: redirectURI, + logoutURI: logoutRedirectURI, + devMode: false, + }) +} + +type clientOpts struct { + redirectURI string + logoutURI string + devMode bool +} + +func createClientWithOpts(t testing.TB, opts clientOpts) string { project, err := Tester.CreateProject(CTX) require.NoError(t, err) - app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + app, err := Tester.CreateOIDCNativeClient(CTX, opts.redirectURI, opts.logoutURI, project.GetId(), opts.devMode) require.NoError(t, err) return app.GetClientId() } diff --git a/internal/auth/repository/eventsourcing/eventstore/user_session.go b/internal/auth/repository/eventsourcing/eventstore/user_session.go index 3fb60fc75e..8bacef942b 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user_session.go +++ b/internal/auth/repository/eventsourcing/eventstore/user_session.go @@ -20,8 +20,3 @@ func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_mode } return model.UserSessionsToModel(userSessions), nil } - -func (repo *UserSessionRepo) ActiveUserSessionCount() int64 { - userSessions, _ := repo.View.ActiveUserSessionsCount() - return int64(userSessions) -} diff --git a/internal/auth/repository/user_session.go b/internal/auth/repository/user_session.go index 0bfaf47e1f..182fe9edea 100644 --- a/internal/auth/repository/user_session.go +++ b/internal/auth/repository/user_session.go @@ -8,5 +8,4 @@ import ( type UserSessionRepository interface { GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error) - ActiveUserSessionCount() int64 } diff --git a/internal/cache/bigcache/bigcache_test.go b/internal/cache/bigcache/bigcache_test.go deleted file mode 100644 index cc48e3240a..0000000000 --- a/internal/cache/bigcache/bigcache_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package bigcache - -import ( - "reflect" - "testing" - - a_cache "github.com/allegro/bigcache" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type TestStruct struct { - Test string -} - -func getBigCacheMock() *Bigcache { - cache, _ := a_cache.NewBigCache(a_cache.DefaultConfig(2000)) - return &Bigcache{cache: cache} -} - -func TestSet(t *testing.T) { - type args struct { - cache *Bigcache - key string - value *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "set cache no err", - args: args{ - cache: getBigCacheMock(), - key: "KEY", - value: &TestStruct{Test: "Test"}, - }, - res: res{ - result: &TestStruct{}, - }, - }, - { - name: "key empty", - args: args{ - cache: getBigCacheMock(), - key: "", - value: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - { - name: "set cache nil value", - args: args{ - cache: getBigCacheMock(), - key: "KEY", - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set(tt.args.key, tt.args.value) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc == nil { - tt.args.cache.Get(tt.args.key, tt.res.result) - if tt.res.result == nil { - t.Errorf("got wrong result should get result: %v ", err) - } - } - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} - -func TestGet(t *testing.T) { - type args struct { - event []*es_models.Event - cache *Bigcache - key string - setValue *TestStruct - getValue *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "get cache no err", - args: args{ - cache: getBigCacheMock(), - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - result: &TestStruct{Test: "Test"}, - }, - }, - { - name: "get cache no key", - args: args{ - cache: getBigCacheMock(), - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - { - name: "get cache no value", - args: args{ - cache: getBigCacheMock(), - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set("KEY", tt.args.setValue) - if err != nil { - t.Errorf("something went wrong") - } - - err = tt.args.cache.Get(tt.args.key, tt.args.getValue) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc == nil && !reflect.DeepEqual(tt.args.getValue, tt.res.result) { - t.Errorf("got wrong result expected: %v actual: %v", tt.res.result, tt.args.getValue) - } - - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} - -func TestDelete(t *testing.T) { - type args struct { - event []*es_models.Event - cache *Bigcache - key string - setValue *TestStruct - getValue *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "delete cache no err", - args: args{ - cache: getBigCacheMock(), - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - }, - res: res{}, - }, - { - name: "get cache no key", - args: args{ - cache: getBigCacheMock(), - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set("KEY", tt.args.setValue) - if err != nil { - t.Errorf("something went wrong") - } - - err = tt.args.cache.Delete(tt.args.key) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} diff --git a/internal/cache/bigcache/cache.go b/internal/cache/bigcache/cache.go deleted file mode 100644 index 68ce57119a..0000000000 --- a/internal/cache/bigcache/cache.go +++ /dev/null @@ -1,67 +0,0 @@ -package bigcache - -import ( - "bytes" - "encoding/gob" - "reflect" - - a_cache "github.com/allegro/bigcache" - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/zerrors" -) - -type Bigcache struct { - cache *a_cache.BigCache -} - -func NewBigcache(c *Config) (*Bigcache, error) { - cacheConfig := a_cache.DefaultConfig(c.CacheLifetime) - cacheConfig.HardMaxCacheSize = c.MaxCacheSizeInMB - cache, err := a_cache.NewBigCache(cacheConfig) - if err != nil { - return nil, err - } - - return &Bigcache{ - cache: cache, - }, nil -} - -func (c *Bigcache) Set(key string, object interface{}) error { - if key == "" || reflect.ValueOf(object).IsNil() { - return zerrors.ThrowInvalidArgument(nil, "BIGCA-du73s", "key or value should not be empty") - } - var b bytes.Buffer - enc := gob.NewEncoder(&b) - if err := enc.Encode(object); err != nil { - return zerrors.ThrowInvalidArgument(err, "BIGCA-RUyxI", "unable to encode object") - } - return c.cache.Set(key, b.Bytes()) -} - -func (c *Bigcache) Get(key string, ptrToObject interface{}) error { - if key == "" || reflect.ValueOf(ptrToObject).IsNil() { - return zerrors.ThrowInvalidArgument(nil, "BIGCA-dksoe", "key or value should not be empty") - } - value, err := c.cache.Get(key) - if err == a_cache.ErrEntryNotFound { - return zerrors.ThrowNotFound(err, "BIGCA-we32s", "not in cache") - } - if err != nil { - logging.Log("BIGCA-ftofbc").WithError(err).Info("read from cache failed") - return zerrors.ThrowInvalidArgument(err, "BIGCA-3idls", "error in reading from cache") - } - - b := bytes.NewBuffer(value) - dec := gob.NewDecoder(b) - - return dec.Decode(ptrToObject) -} - -func (c *Bigcache) Delete(key string) error { - if key == "" { - return zerrors.ThrowInvalidArgument(nil, "BIGCA-clsi2", "key should not be empty") - } - return c.cache.Delete(key) -} diff --git a/internal/cache/bigcache/config.go b/internal/cache/bigcache/config.go deleted file mode 100644 index fa997ea59c..0000000000 --- a/internal/cache/bigcache/config.go +++ /dev/null @@ -1,17 +0,0 @@ -package bigcache - -import ( - "time" - - "github.com/zitadel/zitadel/internal/cache" -) - -type Config struct { - MaxCacheSizeInMB int - //CacheLifetime if set, entries older than the lifetime will be deleted on cleanup (every minute) - CacheLifetime time.Duration -} - -func (c *Config) NewCache() (cache.Cache, error) { - return NewBigcache(c) -} diff --git a/internal/cache/cache.go b/internal/cache/cache.go deleted file mode 100644 index b2eef1cc6f..0000000000 --- a/internal/cache/cache.go +++ /dev/null @@ -1,7 +0,0 @@ -package cache - -type Cache interface { - Set(key string, object interface{}) error - Get(key string, ptrToObject interface{}) error - Delete(key string) error -} diff --git a/internal/cache/config.go b/internal/cache/config.go deleted file mode 100644 index 86c298241d..0000000000 --- a/internal/cache/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package cache - -type Config interface { - NewCache() (Cache, error) -} diff --git a/internal/cache/config/config.go b/internal/cache/config/config.go deleted file mode 100644 index 739387ef47..0000000000 --- a/internal/cache/config/config.go +++ /dev/null @@ -1,59 +0,0 @@ -package config - -import ( - "encoding/json" - - "github.com/zitadel/zitadel/internal/cache" - "github.com/zitadel/zitadel/internal/cache/bigcache" - "github.com/zitadel/zitadel/internal/cache/fastcache" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type CacheConfig struct { - Type string - Config cache.Config -} - -var caches = map[string]func() cache.Config{ - "bigcache": func() cache.Config { return &bigcache.Config{} }, - "fastcache": func() cache.Config { return &fastcache.Config{} }, -} - -func (c *CacheConfig) UnmarshalJSON(data []byte) error { - var rc struct { - Type string - Config json.RawMessage - } - - if err := json.Unmarshal(data, &rc); err != nil { - return zerrors.ThrowInternal(err, "CONFI-98ejs", "unable to unmarshal config") - } - - c.Type = rc.Type - - var err error - c.Config, err = newCacheConfig(c.Type, rc.Config) - if err != nil { - return zerrors.ThrowInternal(err, "CONFI-do9es", "unable create config") - } - - return nil -} - -func newCacheConfig(cacheType string, configData []byte) (cache.Config, error) { - t, ok := caches[cacheType] - if !ok { - return nil, zerrors.ThrowInternal(nil, "CONFI-di328s", "no config") - } - - cacheConfig := t() - if len(configData) == 0 { - return cacheConfig, nil - } - - if err := json.Unmarshal(configData, cacheConfig); err != nil { - return nil, zerrors.ThrowInternal(nil, "CONFI-skei3", "could not read config") - } - - return cacheConfig, nil -} diff --git a/internal/cache/fastcache/config.go b/internal/cache/fastcache/config.go deleted file mode 100644 index 5e68126156..0000000000 --- a/internal/cache/fastcache/config.go +++ /dev/null @@ -1,11 +0,0 @@ -package fastcache - -import "github.com/zitadel/zitadel/internal/cache" - -type Config struct { - MaxCacheSizeInByte int -} - -func (c *Config) NewCache() (cache.Cache, error) { - return NewFastcache(c) -} diff --git a/internal/cache/fastcache/fastcache.go b/internal/cache/fastcache/fastcache.go deleted file mode 100644 index 54b7778c7e..0000000000 --- a/internal/cache/fastcache/fastcache.go +++ /dev/null @@ -1,57 +0,0 @@ -package fastcache - -import ( - "bytes" - "encoding/gob" - "reflect" - - "github.com/VictoriaMetrics/fastcache" - - "github.com/zitadel/zitadel/internal/zerrors" -) - -type Fastcache struct { - cache *fastcache.Cache -} - -func NewFastcache(config *Config) (*Fastcache, error) { - return &Fastcache{ - cache: fastcache.New(config.MaxCacheSizeInByte), - }, nil -} - -func (fc *Fastcache) Set(key string, object interface{}) error { - if key == "" || reflect.ValueOf(object).IsNil() { - return zerrors.ThrowInvalidArgument(nil, "FASTC-87dj3", "key or value should not be empty") - } - var b bytes.Buffer - enc := gob.NewEncoder(&b) - if err := enc.Encode(object); err != nil { - return zerrors.ThrowInvalidArgument(err, "FASTC-RUyxI", "unable to encode object") - } - fc.cache.Set([]byte(key), b.Bytes()) - return nil -} - -func (fc *Fastcache) Get(key string, ptrToObject interface{}) error { - if key == "" || reflect.ValueOf(ptrToObject).IsNil() { - return zerrors.ThrowInvalidArgument(nil, "FASTC-di8es", "key or value should not be empty") - } - data := fc.cache.Get(nil, []byte(key)) - if len(data) == 0 { - return zerrors.ThrowNotFound(nil, "FASTC-xYzSm", "key not found") - } - - b := bytes.NewBuffer(data) - dec := gob.NewDecoder(b) - - return dec.Decode(ptrToObject) -} - -func (fc *Fastcache) Delete(key string) error { - if key == "" { - return zerrors.ThrowInvalidArgument(nil, "FASTC-lod92", "key should not be empty") - } - fc.cache.Del([]byte(key)) - return nil -} diff --git a/internal/cache/fastcache/fastcache_test.go b/internal/cache/fastcache/fastcache_test.go deleted file mode 100644 index 6d4e415338..0000000000 --- a/internal/cache/fastcache/fastcache_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package fastcache - -import ( - "reflect" - "testing" - - "github.com/VictoriaMetrics/fastcache" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type TestStruct struct { - Test string -} - -func TestSet(t *testing.T) { - type args struct { - cache *Fastcache - key string - value *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "set cache no err", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "KEY", - value: &TestStruct{Test: "Test"}, - }, - res: res{ - result: &TestStruct{}, - }, - }, - { - name: "key empty", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "", - value: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - { - name: "set cache nil value", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "KEY", - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set(tt.args.key, tt.args.value) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc == nil { - tt.args.cache.Get(tt.args.key, tt.res.result) - if tt.res.result == nil { - t.Errorf("got wrong result should get result: %v ", err) - } - } - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} - -func TestGet(t *testing.T) { - type args struct { - event []*es_models.Event - cache *Fastcache - key string - setValue *TestStruct - getValue *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "get cache no err", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - result: &TestStruct{Test: "Test"}, - }, - }, - { - name: "get cache no key", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - { - name: "get cache no value", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set("KEY", tt.args.setValue) - if err != nil { - t.Errorf("something went wrong") - } - - err = tt.args.cache.Get(tt.args.key, tt.args.getValue) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc == nil && !reflect.DeepEqual(tt.args.getValue, tt.res.result) { - t.Errorf("got wrong result expected: %v actual: %v", tt.res.result, tt.args.getValue) - } - - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} - -func TestDelete(t *testing.T) { - type args struct { - event []*es_models.Event - cache *Fastcache - key string - setValue *TestStruct - getValue *TestStruct - } - type res struct { - result *TestStruct - errFunc func(err error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - name: "delete cache no err", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - key: "KEY", - setValue: &TestStruct{Test: "Test"}, - }, - res: res{}, - }, - { - name: "get cache no key", - args: args{ - cache: &Fastcache{cache: fastcache.New(2000)}, - setValue: &TestStruct{Test: "Test"}, - getValue: &TestStruct{Test: "Test"}, - }, - res: res{ - errFunc: zerrors.IsErrorInvalidArgument, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.args.cache.Set("KEY", tt.args.setValue) - if err != nil { - t.Errorf("something went wrong") - } - - err = tt.args.cache.Delete(tt.args.key) - - if tt.res.errFunc == nil && err != nil { - t.Errorf("got wrong result should not get err: %v ", err) - } - - if tt.res.errFunc != nil && !tt.res.errFunc(err) { - t.Errorf("got wrong err: %v ", err) - } - }) - } -} diff --git a/internal/cache/generate.go b/internal/cache/generate.go deleted file mode 100644 index 2809d31003..0000000000 --- a/internal/cache/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package cache - -//go:generate mockgen -package mock -destination ./mock/cache.mock.go github.com/zitadel/zitadel/internal/cache Cache diff --git a/internal/cache/mock/cache.mock.go b/internal/cache/mock/cache.mock.go deleted file mode 100644 index 56a238922f..0000000000 --- a/internal/cache/mock/cache.mock.go +++ /dev/null @@ -1,80 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/zitadel/zitadel/internal/cache (interfaces: Cache) -// -// Generated by this command: -// -// mockgen -package mock -destination ./mock/cache.mock.go github.com/zitadel/zitadel/internal/cache Cache -// -// Package mock is a generated GoMock package. -package mock - -import ( - reflect "reflect" - - gomock "go.uber.org/mock/gomock" -) - -// MockCache is a mock of Cache interface. -type MockCache struct { - ctrl *gomock.Controller - recorder *MockCacheMockRecorder -} - -// MockCacheMockRecorder is the mock recorder for MockCache. -type MockCacheMockRecorder struct { - mock *MockCache -} - -// NewMockCache creates a new mock instance. -func NewMockCache(ctrl *gomock.Controller) *MockCache { - mock := &MockCache{ctrl: ctrl} - mock.recorder = &MockCacheMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockCache) EXPECT() *MockCacheMockRecorder { - return m.recorder -} - -// Delete mocks base method. -func (m *MockCache) Delete(arg0 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockCacheMockRecorder) Delete(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockCache)(nil).Delete), arg0) -} - -// Get mocks base method. -func (m *MockCache) Get(arg0 string, arg1 any) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Get indicates an expected call of Get. -func (mr *MockCacheMockRecorder) Get(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockCache)(nil).Get), arg0, arg1) -} - -// Set mocks base method. -func (m *MockCache) Set(arg0 string, arg1 any) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Set", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Set indicates an expected call of Set. -func (mr *MockCacheMockRecorder) Set(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockCache)(nil).Set), arg0, arg1) -} diff --git a/internal/command/unique_constraints_model.go b/internal/command/unique_constraints_model.go index a02a3e18fc..d70b621b27 100644 --- a/internal/command/unique_constraints_model.go +++ b/internal/command/unique_constraints_model.go @@ -2,303 +2,8 @@ package command import ( "context" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/idpconfig" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/member" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/repository/policy" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/repository/user" - "github.com/zitadel/zitadel/internal/repository/usergrant" ) -type UniqueConstraintReadModel struct { - eventstore.WriteModel - - UniqueConstraints []*domain.UniqueConstraintMigration - commandProvider commandProvider - ctx context.Context -} - type commandProvider interface { domainPolicyWriteModel(ctx context.Context, orgID string) (*PolicyDomainWriteModel, error) } - -func NewUniqueConstraintReadModel(ctx context.Context, provider commandProvider) *UniqueConstraintReadModel { - return &UniqueConstraintReadModel{ - ctx: ctx, - commandProvider: provider, - } -} - -func (rm *UniqueConstraintReadModel) AppendEvents(events ...eventstore.Event) { - rm.WriteModel.AppendEvents(events...) -} - -func (rm *UniqueConstraintReadModel) Reduce() error { - for _, event := range rm.Events { - switch e := event.(type) { - case *org.OrgAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name)) - case *org.OrgChangedEvent: - rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name)) - case *org.DomainVerifiedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgDomainUniqueConstraint(e.Domain)) - case *org.DomainRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.UniqueOrgDomain) - case *instance.IDPConfigAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)) - case *instance.IDPConfigChangedEvent: - if e.Name == nil { - continue - } - rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner)) - case *instance.IDPConfigRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType) - case *org.IDPConfigAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)) - case *org.IDPConfigChangedEvent: - if e.Name == nil { - continue - } - rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner)) - case *org.IDPConfigRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType) - case *instance.MailTextAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language)) - case *org.MailTextAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language)) - case *org.MailTextRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.UniqueMailText) - case *project.ProjectAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)) - case *project.ProjectChangeEvent: - if e.Name == nil { - continue - } - rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner)) - case *project.ProjectRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.UniqueProjectnameType) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueAppNameType) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, member.UniqueMember) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueRoleType) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueGrantType) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueProjectGrantMemberType) - case *project.ApplicationAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID)) - case *project.ApplicationChangedEvent: - rm.changeUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID)) - case *project.SAMLConfigAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddSAMLConfigEntityIDUniqueConstraint(e.EntityID)) - case *project.SAMLConfigChangedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewRemoveSAMLConfigEntityIDUniqueConstraint(e.EntityID)) - case *project.ApplicationRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.AppID, project.UniqueAppNameType) - case *project.GrantAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID, project.NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.Aggregate().ID)) - case *project.GrantRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID, project.UniqueGrantType) - case *project.GrantMemberAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.Aggregate().ID, e.UserID, e.GrantID)) - case *project.GrantMemberRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType) - case *project.GrantMemberCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType) - case *project.RoleAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.Aggregate().ID)) - case *project.RoleRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Key, project.UniqueRoleType) - case *user.HumanAddedEvent: - policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner) - if err != nil { - logging.Log("COMMAND-0k9Gs").WithError(err).Error("could not read policy for human added event unique constraint") - continue - } - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain)) - case *user.HumanRegisteredEvent: - policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner) - if err != nil { - logging.Log("COMMAND-m9fod").WithError(err).Error("could not read policy for human registered event unique constraint") - continue - } - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain)) - case *user.MachineAddedEvent: - policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner) - if err != nil { - logging.Log("COMMAND-2n8vs").WithError(err).Error("could not read policy for machine added event unique constraint") - continue - } - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain)) - case *user.UserRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername) - rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueUserIDPLinkType) - case *user.UsernameChangedEvent: - policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner) - if err != nil { - logging.Log("COMMAND-5n8gk").WithError(err).Error("could not read policy for username changed event unique constraint") - continue - } - rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain)) - case *user.DomainClaimedEvent: - policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner) - if err != nil { - logging.Log("COMMAND-xb8uf").WithError(err).Error("could not read policy for domain claimed event unique constraint") - continue - } - rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain)) - case *user.UserIDPLinkAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID)) - case *user.UserIDPLinkRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType) - case *user.UserIDPLinkCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType) - case *usergrant.UserGrantAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID)) - case *usergrant.UserGrantRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant) - case *usergrant.UserGrantCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant) - case *instance.MemberAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID)) - case *instance.MemberRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - case *instance.MemberCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - case *org.MemberAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID)) - case *org.MemberRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - case *org.MemberCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - case *project.MemberAddedEvent: - rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID)) - case *project.MemberRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - case *project.MemberCascadeRemovedEvent: - rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember) - } - } - return rm.WriteModel.Reduce() -} - -func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder { - return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). - AddQuery().AggregateTypes( - instance.AggregateType, - org.AggregateType, - project.AggregateType, - user.AggregateType, - usergrant.AggregateType). - EventTypes( - org.OrgAddedEventType, - org.OrgChangedEventType, - org.OrgDomainVerifiedEventType, - org.OrgDomainRemovedEventType, - instance.IDPConfigAddedEventType, - instance.IDPConfigChangedEventType, - instance.IDPConfigRemovedEventType, - org.IDPConfigAddedEventType, - org.IDPConfigChangedEventType, - org.IDPConfigRemovedEventType, - instance.MailTextAddedEventType, - org.MailTextAddedEventType, - org.MailTextRemovedEventType, - project.ProjectAddedType, - project.ProjectChangedType, - project.ProjectRemovedType, - project.ApplicationAddedType, - project.ApplicationChangedType, - project.ApplicationRemovedType, - project.GrantAddedType, - project.GrantRemovedType, - project.GrantMemberAddedType, - project.GrantMemberRemovedType, - project.GrantMemberCascadeRemovedType, - project.RoleAddedType, - project.RoleRemovedType, - user.UserV1AddedType, - user.UserV1RegisteredType, - user.HumanAddedType, - user.HumanRegisteredType, - user.MachineAddedEventType, - user.UserUserNameChangedType, - user.UserDomainClaimedType, - user.UserRemovedType, - user.UserIDPLinkAddedType, - user.UserIDPLinkRemovedType, - user.UserIDPLinkCascadeRemovedType, - usergrant.UserGrantAddedType, - usergrant.UserGrantRemovedType, - usergrant.UserGrantCascadeRemovedType, - instance.MemberAddedEventType, - instance.MemberRemovedEventType, - instance.MemberCascadeRemovedEventType, - org.MemberAddedEventType, - org.MemberRemovedEventType, - org.MemberCascadeRemovedEventType, - project.MemberAddedType, - project.MemberRemovedType, - project.MemberCascadeRemovedType). - Builder() -} - -func (rm *UniqueConstraintReadModel) getUniqueConstraint(aggregateID, objectID, constraintType string) *domain.UniqueConstraintMigration { - for _, uniqueConstraint := range rm.UniqueConstraints { - if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType { - return uniqueConstraint - } - } - return nil -} - -func (rm *UniqueConstraintReadModel) addUniqueConstraint(aggregateID, objectID string, constraint *eventstore.UniqueConstraint) { - migrateUniqueConstraint := &domain.UniqueConstraintMigration{ - AggregateID: aggregateID, - ObjectID: objectID, - UniqueType: constraint.UniqueType, - UniqueField: constraint.UniqueField, - ErrorMessage: constraint.ErrorMessage, - } - rm.UniqueConstraints = append(rm.UniqueConstraints, migrateUniqueConstraint) -} - -func (rm *UniqueConstraintReadModel) changeUniqueConstraint(aggregateID, objectID string, constraint *eventstore.UniqueConstraint) { - for i, uniqueConstraint := range rm.UniqueConstraints { - if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraint.UniqueType { - rm.UniqueConstraints[i] = &domain.UniqueConstraintMigration{ - AggregateID: aggregateID, - ObjectID: objectID, - UniqueType: constraint.UniqueType, - UniqueField: constraint.UniqueField, - ErrorMessage: constraint.ErrorMessage, - } - return - } - } -} - -func (rm *UniqueConstraintReadModel) removeUniqueConstraint(aggregateID, objectID, constraintType string) { - for i, uniqueConstraint := range rm.UniqueConstraints { - if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType { - copy(rm.UniqueConstraints[i:], rm.UniqueConstraints[i+1:]) - rm.UniqueConstraints[len(rm.UniqueConstraints)-1] = nil - rm.UniqueConstraints = rm.UniqueConstraints[:len(rm.UniqueConstraints)-1] - return - } - } -} - -func (rm *UniqueConstraintReadModel) listRemoveUniqueConstraint(aggregateID, constraintType string) { - for i := len(rm.UniqueConstraints) - 1; i >= 0; i-- { - if rm.UniqueConstraints[i].AggregateID == aggregateID && rm.UniqueConstraints[i].UniqueType == constraintType { - copy(rm.UniqueConstraints[i:], rm.UniqueConstraints[i+1:]) - rm.UniqueConstraints[len(rm.UniqueConstraints)-1] = nil - rm.UniqueConstraints = rm.UniqueConstraints[:len(rm.UniqueConstraints)-1] - } - } -} diff --git a/internal/database/database.go b/internal/database/database.go index 30e03150c5..cd72d6d242 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "reflect" + "strings" "github.com/mitchellh/mapstructure" "github.com/zitadel/logging" @@ -84,6 +85,7 @@ func (db *DB) QueryRowContext(ctx context.Context, scan func(row *sql.Row) error }() row := tx.QueryRowContext(ctx, query, args...) + logging.OnError(row.Err()).Error("unexpected query error") err = scan(row) if err != nil { @@ -170,3 +172,9 @@ func (c Config) Password() string { func (c Config) Type() string { return c.connector.Type() } + +func EscapeLikeWildcards(value string) string { + value = strings.ReplaceAll(value, "%", "\\%") + value = strings.ReplaceAll(value, "_", "\\_") + return value +} diff --git a/internal/domain/mfa.go b/internal/domain/mfa.go index 65ad9486fd..3b408109f7 100644 --- a/internal/domain/mfa.go +++ b/internal/domain/mfa.go @@ -13,10 +13,6 @@ const ( stateCount ) -func (f MFAState) Valid() bool { - return f >= 0 && f < stateCount -} - type MultifactorConfigs struct { OTP OTPConfig } diff --git a/internal/domain/notification.go b/internal/domain/notification.go index f4af3ea515..756c400c66 100644 --- a/internal/domain/notification.go +++ b/internal/domain/notification.go @@ -9,10 +9,6 @@ const ( notificationCount ) -func (f NotificationType) Valid() bool { - return f >= 0 && f < notificationCount -} - type NotificationProviderState int32 const ( diff --git a/internal/domain/policy.go b/internal/domain/policy.go index 457152f3c3..6efe5520d7 100644 --- a/internal/domain/policy.go +++ b/internal/domain/policy.go @@ -10,10 +10,6 @@ const ( policyStateCount ) -func (f PolicyState) Valid() bool { - return f >= 0 && f < policyStateCount -} - func (s PolicyState) Exists() bool { return s != PolicyStateUnspecified && s != PolicyStateRemoved } diff --git a/internal/domain/policy_label.go b/internal/domain/policy_label.go index 323f45c67a..b9f2560ae0 100644 --- a/internal/domain/policy_label.go +++ b/internal/domain/policy_label.go @@ -83,11 +83,3 @@ func (f LabelPolicy) IsValid() error { } return nil } - -func (f LabelPolicyState) Valid() bool { - return f >= 0 && f < labelPolicyStateCount -} - -func (s LabelPolicyState) Exists() bool { - return s != LabelPolicyStateUnspecified && s != LabelPolicyStateRemoved -} diff --git a/internal/domain/policy_login.go b/internal/domain/policy_login.go index c898ea2544..6c4214724d 100644 --- a/internal/domain/policy_login.go +++ b/internal/domain/policy_login.go @@ -66,12 +66,6 @@ func (p IDPProvider) IsValid() bool { return p.IDPConfigID != "" } -// DisplayName returns the name or a default -// to be used when always a name must be displayed (e.g. login) -func (p IDPProvider) DisplayName() string { - return IDPName(p.Name, p.IDPType) -} - type PasswordlessType int32 const ( @@ -88,7 +82,3 @@ func (f PasswordlessType) Valid() bool { func (p *LoginPolicy) HasSecondFactors() bool { return len(p.SecondFactors) > 0 } - -func (p *LoginPolicy) HasMultiFactors() bool { - return len(p.MultiFactors) > 0 -} diff --git a/internal/domain/project_grant.go b/internal/domain/project_grant.go index 09604913a8..fecf38ec63 100644 --- a/internal/domain/project_grant.go +++ b/internal/domain/project_grant.go @@ -11,11 +11,6 @@ type ProjectGrant struct { RoleKeys []string } -type ProjectGrantIDs struct { - ProjectID string - GrantID string -} - type ProjectGrantState int32 const ( diff --git a/internal/domain/project_grant_member.go b/internal/domain/project_grant_member.go index 8c1a840437..bc3fd902fa 100644 --- a/internal/domain/project_grant_member.go +++ b/internal/domain/project_grant_member.go @@ -12,17 +12,6 @@ type ProjectGrantMember struct { Roles []string } -func NewProjectGrantMember(aggregateID, userID, grantID string, roles ...string) *ProjectGrantMember { - return &ProjectGrantMember{ - ObjectRoot: es_models.ObjectRoot{ - AggregateID: aggregateID, - }, - GrantID: grantID, - UserID: userID, - Roles: roles, - } -} - func (i *ProjectGrantMember) IsValid() bool { return i.AggregateID != "" && i.GrantID != "" && i.UserID != "" && len(i.Roles) != 0 } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index b21a5e2a61..16dc2800b7 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -9,10 +9,6 @@ const ( identityProviderCount ) -func (f IdentityProviderType) Valid() bool { - return f >= 0 && f < identityProviderCount -} - type IdentityProviderState int32 const ( @@ -22,7 +18,3 @@ const ( idpProviderState ) - -func (s IdentityProviderState) Valid() bool { - return s >= 0 && s < idpProviderState -} diff --git a/internal/domain/step.go b/internal/domain/step.go deleted file mode 100644 index dc3641389b..0000000000 --- a/internal/domain/step.go +++ /dev/null @@ -1,29 +0,0 @@ -package domain - -type Step int - -const ( - Step1 Step = iota + 1 - Step2 - Step3 - Step4 - Step5 - Step6 - Step7 - Step8 - Step9 - Step10 - Step11 - Step12 - Step13 - Step14 - Step15 - Step16 - Step17 - Step18 - Step19 - Step20 - Step21 - //StepCount marks the the length of possible steps (StepCount-1 == last possible step) - StepCount -) diff --git a/internal/domain/unique_constraint_migration.go b/internal/domain/unique_constraint_migration.go deleted file mode 100644 index f699e68ae3..0000000000 --- a/internal/domain/unique_constraint_migration.go +++ /dev/null @@ -1,9 +0,0 @@ -package domain - -type UniqueConstraintMigration struct { - AggregateID string - ObjectID string - UniqueType string - UniqueField string - ErrorMessage string -} diff --git a/internal/domain/user.go b/internal/domain/user.go index 18fa2db9af..7450d06417 100644 --- a/internal/domain/user.go +++ b/internal/domain/user.go @@ -1,10 +1,5 @@ package domain -type User interface { - GetUsername() string - GetState() UserState -} - type UserState int32 const ( @@ -19,10 +14,6 @@ const ( userStateCount ) -func (f UserState) Valid() bool { - return f >= 0 && f < userStateCount -} - func (s UserState) Exists() bool { return s != UserStateUnspecified && s != UserStateDeleted } @@ -40,10 +31,6 @@ const ( userTypeCount ) -func (f UserType) Valid() bool { - return f >= 0 && f < userTypeCount -} - type UserAuthMethodType int32 const ( @@ -58,10 +45,6 @@ const ( userAuthMethodTypeCount ) -func (f UserAuthMethodType) Valid() bool { - return f >= 0 && f < userAuthMethodTypeCount -} - // HasMFA checks whether the user authenticated with multiple auth factors. // This can either be true if the list contains a [UserAuthMethodType] which by itself is MFA (e.g. [UserAuthMethodTypePasswordless]) // or if multiple factors were used (e.g. [UserAuthMethodTypePassword] and [UserAuthMethodTypeU2F]) diff --git a/internal/domain/user_membership.go b/internal/domain/user_membership.go deleted file mode 100644 index ae786237ea..0000000000 --- a/internal/domain/user_membership.go +++ /dev/null @@ -1,29 +0,0 @@ -package domain - -import "time" - -type UserMembership struct { - UserID string - MemberType MemberType - AggregateID string - //ObjectID differs from aggregate id if obejct is sub of an aggregate - ObjectID string - - Roles []string - DisplayName string - CreationDate time.Time - ChangeDate time.Time - ResourceOwner string - ResourceOwnerName string - Sequence uint64 -} - -type MemberType int32 - -const ( - MemberTypeUnspecified MemberType = iota - MemberTypeOrganisation - MemberTypeProject - MemberTypeProjectGrant - MemberTypeIam -) diff --git a/internal/eventstore/v3/sequence.go b/internal/eventstore/v3/sequence.go index 994645eab2..8d84ef4755 100644 --- a/internal/eventstore/v3/sequence.go +++ b/internal/eventstore/v3/sequence.go @@ -26,7 +26,7 @@ func latestSequences(ctx context.Context, tx *sql.Tx, commands []eventstore.Comm sequences := commandsToSequences(ctx, commands) conditions, args := sequencesToSql(sequences) - rows, err := tx.QueryContext(ctx, fmt.Sprintf(latestSequencesStmt, strings.Join(conditions, " OR ")), args...) + rows, err := tx.QueryContext(ctx, fmt.Sprintf(latestSequencesStmt, strings.Join(conditions, " UNION ALL ")), args...) if err != nil { return nil, zerrors.ThrowInternal(err, "V3-5jU5z", "Errors.Internal") } @@ -92,7 +92,7 @@ func sequencesToSql(sequences []*latestSequence) (conditions []string, args []an conditions = make([]string, len(sequences)) for i, sequence := range sequences { - conditions[i] = fmt.Sprintf("(instance_id = $%d AND aggregate_type = $%d AND aggregate_id = $%d)", + conditions[i] = fmt.Sprintf(`(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $%d AND aggregate_type = $%d AND aggregate_id = $%d ORDER BY "sequence" DESC LIMIT 1)`, i*argsPerCondition+1, i*argsPerCondition+2, i*argsPerCondition+3, diff --git a/internal/eventstore/v3/sequence_test.go b/internal/eventstore/v3/sequence_test.go index 55ee73831d..d755c0dbd2 100644 --- a/internal/eventstore/v3/sequence_test.go +++ b/internal/eventstore/v3/sequence_test.go @@ -247,7 +247,7 @@ func Test_sequencesToSql(t *testing.T) { }, }, wantConditions: []string{ - "(instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3)", + `(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3 ORDER BY "sequence" DESC LIMIT 1)`, }, wantArgs: []any{ "instance", @@ -266,8 +266,8 @@ func Test_sequencesToSql(t *testing.T) { }, }, wantConditions: []string{ - "(instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3)", - "(instance_id = $4 AND aggregate_type = $5 AND aggregate_id = $6)", + `(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3 ORDER BY "sequence" DESC LIMIT 1)`, + `(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $4 AND aggregate_type = $5 AND aggregate_id = $6 ORDER BY "sequence" DESC LIMIT 1)`, }, wantArgs: []any{ "instance", diff --git a/internal/eventstore/v3/sequences_query.sql b/internal/eventstore/v3/sequences_query.sql index fb164013dc..468a275253 100644 --- a/internal/eventstore/v3/sequences_query.sql +++ b/internal/eventstore/v3/sequences_query.sql @@ -1,17 +1,5 @@ -with existing as ( - SELECT - instance_id - , aggregate_type - , aggregate_id - , MAX("sequence") "sequence" - FROM - eventstore.events2 existing - WHERE - %s - GROUP BY - instance_id - , aggregate_type - , aggregate_id +WITH existing AS ( + %s ) SELECT e.instance_id , e.owner @@ -23,8 +11,8 @@ FROM JOIN existing ON - e.instance_id = existing.instance_id - AND e.aggregate_type = existing.aggregate_type - AND e.aggregate_id = existing.aggregate_id - AND e.sequence = existing.sequence + e.instance_id = existing.instance_id + AND e.aggregate_type = existing.aggregate_type + AND e.aggregate_id = existing.aggregate_id + AND e.sequence = existing.sequence FOR UPDATE; \ No newline at end of file diff --git a/internal/iam/model/iam.go b/internal/iam/model/iam.go deleted file mode 100644 index a87276eede..0000000000 --- a/internal/iam/model/iam.go +++ /dev/null @@ -1,32 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type Step int - -const ( - Step1 Step = iota + 1 - Step2 - Step3 - Step4 - Step5 - Step6 - Step7 - Step8 - Step9 - Step10 - //StepCount marks the the length of possible steps (StepCount-1 == last possible step) - StepCount -) - -type IAM struct { - es_models.ObjectRoot - DefaultOrgID string - IAMProjectID string - SetUpDone domain.Step - SetUpStarted domain.Step - Members []*IAMMember -} diff --git a/internal/iam/model/iam_member.go b/internal/iam/model/iam_member.go deleted file mode 100644 index c808b0a3d0..0000000000 --- a/internal/iam/model/iam_member.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -import es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - -type IAMMember struct { - es_models.ObjectRoot - - UserID string - Roles []string -} - -func NewIAMMember(iamID, userID string) *IAMMember { - return &IAMMember{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, UserID: userID} -} - -func (i *IAMMember) IsValid() bool { - return i.AggregateID != "" && i.UserID != "" && len(i.Roles) != 0 -} diff --git a/internal/iam/model/idp_config.go b/internal/iam/model/idp_config.go deleted file mode 100644 index d80a039e90..0000000000 --- a/internal/iam/model/idp_config.go +++ /dev/null @@ -1,110 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/crypto" - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type IDPConfig struct { - es_models.ObjectRoot - IDPConfigID string - Type IdpConfigType - Name string - StylingType IDPStylingType - State IDPConfigState - OIDCConfig *OIDCIDPConfig - JWTIDPConfig *JWTIDPConfig -} - -type OIDCIDPConfig struct { - es_models.ObjectRoot - IDPConfigID string - ClientID string - ClientSecret *crypto.CryptoValue - ClientSecretString string - Issuer string - Scopes []string - IDPDisplayNameMapping OIDCMappingField - UsernameMapping OIDCMappingField -} - -type JWTIDPConfig struct { - es_models.ObjectRoot - IDPConfigID string - JWTEndpoint string - Issuer string - KeysEndpoint string -} - -type IdpConfigType int32 - -const ( - IDPConfigTypeOIDC IdpConfigType = iota - IDPConfigTypeSAML - IDPConfigTypeJWT -) - -type IDPConfigState int32 - -const ( - IDPConfigStateActive IDPConfigState = iota - IDPConfigStateInactive - IDPConfigStateRemoved -) - -type IDPStylingType int32 - -const ( - IDPStylingTypeUnspecified IDPStylingType = iota - IDPStylingTypeGoogle -) - -type OIDCMappingField int32 - -const ( - OIDCMappingFieldUnspecified OIDCMappingField = iota - OIDCMappingFieldPreferredLoginName - OIDCMappingFieldEmail -) - -func NewIDPConfig(iamID, idpID string) *IDPConfig { - return &IDPConfig{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, IDPConfigID: idpID} -} - -func (idp *IDPConfig) IsValid(includeConfig bool) bool { - if idp.Name == "" || idp.AggregateID == "" { - return false - } - if !includeConfig { - return true - } - if idp.Type == IDPConfigTypeOIDC && !idp.OIDCConfig.IsValid(true) { - return false - } - return true -} - -func (oi *OIDCIDPConfig) IsValid(withSecret bool) bool { - if withSecret { - return oi.ClientID != "" && oi.Issuer != "" && oi.ClientSecretString != "" - } - return oi.ClientID != "" && oi.Issuer != "" -} - -func (oi *OIDCIDPConfig) CryptSecret(crypt crypto.Crypto) error { - cryptedSecret, err := crypto.Crypt([]byte(oi.ClientSecretString), crypt) - if err != nil { - return err - } - oi.ClientSecret = cryptedSecret - return nil -} - -func (st IDPStylingType) GetCSSClass() string { - switch st { - case IDPStylingTypeGoogle: - return "google" - default: - return "" - } -} diff --git a/internal/iam/model/idp_config_view.go b/internal/iam/model/idp_config_view.go deleted file mode 100644 index 6ba6a8c977..0000000000 --- a/internal/iam/model/idp_config_view.go +++ /dev/null @@ -1,85 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/crypto" - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type IDPConfigView struct { - AggregateID string - IDPConfigID string - Name string - StylingType IDPStylingType - AutoRegister bool - State IDPConfigState - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 - IDPProviderType IDPProviderType - - IsOIDC bool - OIDCClientID string - OIDCClientSecret *crypto.CryptoValue - OIDCIssuer string - OIDCScopes []string - OIDCIDPDisplayNameMapping OIDCMappingField - OIDCUsernameMapping OIDCMappingField - OAuthAuthorizationEndpoint string - OAuthTokenEndpoint string - JWTEndpoint string - JWTIssuer string - JWTKeysEndpoint string - JWTHeaderName string -} - -type IDPConfigSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn IDPConfigSearchKey - Asc bool - Queries []*IDPConfigSearchQuery -} - -type IDPConfigSearchKey int32 - -const ( - IDPConfigSearchKeyUnspecified IDPConfigSearchKey = iota - IDPConfigSearchKeyName - IDPConfigSearchKeyAggregateID - IDPConfigSearchKeyIdpConfigID - IDPConfigSearchKeyIdpProviderType - IDPConfigSearchKeyInstanceID - IDPConfigSearchKeyOwnerRemoved -) - -type IDPConfigSearchQuery struct { - Key IDPConfigSearchKey - Method domain.SearchMethod - Value interface{} -} - -type IDPConfigSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*IDPConfigView - Sequence uint64 - Timestamp time.Time -} - -func (r *IDPConfigSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-Mv9sd", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} - -func (r *IDPConfigSearchRequest) AppendMyOrgQuery(orgID, iamID string) { - r.Queries = append(r.Queries, &IDPConfigSearchQuery{Key: IDPConfigSearchKeyAggregateID, Method: domain.SearchMethodIsOneOf, Value: []string{orgID, iamID}}) -} diff --git a/internal/iam/model/idp_provider_view.go b/internal/iam/model/idp_provider_view.go deleted file mode 100644 index 182521cee2..0000000000 --- a/internal/iam/model/idp_provider_view.go +++ /dev/null @@ -1,70 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type IDPProviderView struct { - AggregateID string - IDPConfigID string - IDPProviderType IDPProviderType - Name string - StylingType IDPStylingType - IDPConfigType IdpConfigType - IDPState IDPConfigState - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type IDPProviderSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn IDPProviderSearchKey - Asc bool - Queries []*IDPProviderSearchQuery -} - -type IDPProviderSearchKey int32 - -const ( - IDPProviderSearchKeyUnspecified IDPProviderSearchKey = iota - IDPProviderSearchKeyAggregateID - IDPProviderSearchKeyIdpConfigID - IDPProviderSearchKeyState - IDPProviderSearchKeyInstanceID - IDPProviderSearchKeyOwnerRemoved -) - -type IDPProviderSearchQuery struct { - Key IDPProviderSearchKey - Method domain.SearchMethod - Value interface{} -} - -type IDPProviderSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*IDPProviderView - Sequence uint64 - Timestamp time.Time -} - -func (r *IDPProviderSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-3n8fs", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} - -func (r *IDPProviderSearchRequest) AppendAggregateIDQuery(aggregateID string) { - r.Queries = append(r.Queries, &IDPProviderSearchQuery{Key: IDPProviderSearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID}) -} diff --git a/internal/iam/model/label_policy.go b/internal/iam/model/label_policy.go deleted file mode 100644 index bbed48334c..0000000000 --- a/internal/iam/model/label_policy.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type LabelPolicy struct { - models.ObjectRoot - - State PolicyState - Default bool - PrimaryColor string - BackgroundColor string - FontColor string - WarnColor string - PrimaryColorDark string - BackgroundColorDark string - FontColorDark string - WarnColorDark string - HideLoginNameSuffix bool -} - -func (p *LabelPolicy) IsValid() bool { - return p.ObjectRoot.AggregateID != "" -} diff --git a/internal/iam/model/label_policy_view.go b/internal/iam/model/label_policy_view.go index cdab0b44b9..c1995658f7 100644 --- a/internal/iam/model/label_policy_view.go +++ b/internal/iam/model/label_policy_view.go @@ -1,47 +1,9 @@ package model import ( - "time" - "github.com/zitadel/zitadel/internal/domain" ) -type LabelPolicyView struct { - AggregateID string - PrimaryColor string - BackgroundColor string - WarnColor string - FontColor string - LogoURL string - IconURL string - - PrimaryColorDark string - BackgroundColorDark string - WarnColorDark string - FontColorDark string - LogoDarkURL string - IconDarkURL string - FontURL string - - HideLoginNameSuffix bool - ErrorMsgPopup bool - DisableWatermark bool - - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type LabelPolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn LabelPolicySearchKey - Asc bool - Queries []*LabelPolicySearchQuery -} - type LabelPolicySearchKey int32 const ( @@ -57,12 +19,3 @@ type LabelPolicySearchQuery struct { Method domain.SearchMethod Value interface{} } - -type LabelPolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*LabelPolicyView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/model/login_policy.go b/internal/iam/model/login_policy.go index 09f6ec1bc3..65f9d43cc1 100644 --- a/internal/iam/model/login_policy.go +++ b/internal/iam/model/login_policy.go @@ -1,90 +1,8 @@ package model -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type LoginPolicy struct { - models.ObjectRoot - - State PolicyState - Default bool - AllowUsernamePassword bool - AllowRegister bool - AllowExternalIdp bool - IDPProviders []*IDPProvider - ForceMFA bool - SecondFactors []domain.SecondFactorType - MultiFactors []domain.MultiFactorType - PasswordlessType PasswordlessType -} - -type IDPProvider struct { - models.ObjectRoot - Type IDPProviderType - IDPConfigID string -} - type PolicyState int32 const ( PolicyStateActive PolicyState = iota PolicyStateRemoved ) - -type IDPProviderType int32 - -const ( - IDPProviderTypeSystem IDPProviderType = iota - IDPProviderTypeOrg -) - -type MultiFactorType int32 - -const ( - MultiFactorTypeUnspecified MultiFactorType = iota - MultiFactorTypeU2FWithPIN -) - -type PasswordlessType int32 - -const ( - PasswordlessTypeNotAllowed PasswordlessType = iota - PasswordlessTypeAllowed -) - -func (p *LoginPolicy) IsValid() bool { - return p.ObjectRoot.AggregateID != "" -} - -func (p *IDPProvider) IsValid() bool { - return p.ObjectRoot.AggregateID != "" && p.IDPConfigID != "" -} - -func (p *LoginPolicy) GetIdpProvider(id string) (int, *IDPProvider) { - for i, m := range p.IDPProviders { - if m.IDPConfigID == id { - return i, m - } - } - return -1, nil -} - -func (p *LoginPolicy) GetSecondFactor(mfaType domain.SecondFactorType) (int, domain.SecondFactorType) { - for i, m := range p.SecondFactors { - if m == mfaType { - return i, m - } - } - return -1, 0 -} - -func (p *LoginPolicy) GetMultiFactor(mfaType domain.MultiFactorType) (int, domain.MultiFactorType) { - for i, m := range p.MultiFactors { - if m == mfaType { - return i, m - } - } - return -1, 0 -} diff --git a/internal/iam/model/login_policy_view.go b/internal/iam/model/login_policy_view.go deleted file mode 100644 index c4aaafa828..0000000000 --- a/internal/iam/model/login_policy_view.go +++ /dev/null @@ -1,129 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type LoginPolicyView struct { - AggregateID string - AllowUsernamePassword bool - AllowRegister bool - AllowExternalIDP bool - ForceMFA bool - HidePasswordReset bool - PasswordlessType PasswordlessType - SecondFactors []domain.SecondFactorType - MultiFactors []domain.MultiFactorType - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type LoginPolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn LoginPolicySearchKey - Asc bool - Queries []*LoginPolicySearchQuery -} - -type LoginPolicySearchKey int32 - -const ( - LoginPolicySearchKeyUnspecified LoginPolicySearchKey = iota - LoginPolicySearchKeyAggregateID - LoginPolicySearchKeyDefault -) - -type LoginPolicySearchQuery struct { - Key LoginPolicySearchKey - Method domain.SearchMethod - Value interface{} -} - -type LoginPolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*LoginPolicyView - Sequence uint64 - Timestamp time.Time -} - -func (p *LoginPolicyView) HasSecondFactors() bool { - if p.SecondFactors == nil || len(p.SecondFactors) == 0 { - return false - } - return true -} - -func (p *LoginPolicyView) HasMultiFactors() bool { - if p.MultiFactors == nil || len(p.MultiFactors) == 0 { - return false - } - return true -} - -func (p *LoginPolicyView) ToLoginPolicyDomain() *domain.LoginPolicy { - return &domain.LoginPolicy{ - ObjectRoot: models.ObjectRoot{ - AggregateID: p.AggregateID, - CreationDate: p.CreationDate, - ChangeDate: p.ChangeDate, - Sequence: p.Sequence, - }, - Default: p.Default, - AllowUsernamePassword: p.AllowUsernamePassword, - AllowRegister: p.AllowRegister, - AllowExternalIDP: p.AllowExternalIDP, - ForceMFA: p.ForceMFA, - HidePasswordReset: p.HidePasswordReset, - PasswordlessType: passwordLessTypeToDomain(p.PasswordlessType), - SecondFactors: secondFactorsToDomain(p.SecondFactors), - MultiFactors: multiFactorsToDomain(p.MultiFactors), - } -} - -func passwordLessTypeToDomain(passwordless PasswordlessType) domain.PasswordlessType { - switch passwordless { - case PasswordlessTypeNotAllowed: - return domain.PasswordlessTypeNotAllowed - case PasswordlessTypeAllowed: - return domain.PasswordlessTypeAllowed - default: - return domain.PasswordlessTypeNotAllowed - } -} - -func secondFactorsToDomain(types []domain.SecondFactorType) []domain.SecondFactorType { - secondfactors := make([]domain.SecondFactorType, len(types)) - for i, secondfactorType := range types { - switch secondfactorType { - case domain.SecondFactorTypeU2F: - secondfactors[i] = domain.SecondFactorTypeU2F - case domain.SecondFactorTypeTOTP: - secondfactors[i] = domain.SecondFactorTypeTOTP - case domain.SecondFactorTypeOTPEmail: - secondfactors[i] = domain.SecondFactorTypeOTPEmail - case domain.SecondFactorTypeOTPSMS: - secondfactors[i] = domain.SecondFactorTypeOTPSMS - } - } - return secondfactors -} - -func multiFactorsToDomain(types []domain.MultiFactorType) []domain.MultiFactorType { - multifactors := make([]domain.MultiFactorType, len(types)) - for i, multifactorType := range types { - switch multifactorType { - case domain.MultiFactorTypeU2FWithPIN: - multifactors[i] = domain.MultiFactorTypeU2FWithPIN - } - } - return multifactors -} diff --git a/internal/iam/model/mail_template.go b/internal/iam/model/mail_template.go deleted file mode 100644 index c1b8dc9a04..0000000000 --- a/internal/iam/model/mail_template.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type MailTemplate struct { - models.ObjectRoot - - State PolicyState - Default bool - Template []byte -} - -func (p *MailTemplate) IsValid() bool { - return p.ObjectRoot.AggregateID != "" -} diff --git a/internal/iam/model/mail_text.go b/internal/iam/model/mail_text.go deleted file mode 100644 index 1ca22c37bb..0000000000 --- a/internal/iam/model/mail_text.go +++ /dev/null @@ -1,29 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type MailTexts struct { - Texts []*MailText - Default bool -} -type MailText struct { - models.ObjectRoot - - State PolicyState - Default bool - MailTextType string - Language string - Title string - PreHeader string - Subject string - Greeting string - Text string - ButtonText string - FooterText string -} - -func (p *MailText) IsValid() bool { - return p.ObjectRoot.AggregateID != "" -} diff --git a/internal/iam/model/message_text_view.go b/internal/iam/model/message_text_view.go deleted file mode 100644 index 496bcee21c..0000000000 --- a/internal/iam/model/message_text_view.go +++ /dev/null @@ -1,59 +0,0 @@ -package model - -import ( - "time" - - "golang.org/x/text/language" - - "github.com/zitadel/zitadel/internal/domain" -) - -type MessageTextView struct { - AggregateID string - MessageTextType string - Language language.Tag - Title string - PreHeader string - Subject string - Greeting string - Text string - ButtonText string - FooterText string - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type MessageTextSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn MessageTextSearchKey - Asc bool - Queries []*MessageTextSearchQuery -} - -type MessageTextSearchKey int32 - -const ( - MessageTextSearchKeyUnspecified MessageTextSearchKey = iota - MessageTextSearchKeyAggregateID - MessageTextSearchKeyMessageTextType - MessageTextSearchKeyLanguage -) - -type MessageTextSearchQuery struct { - Key MessageTextSearchKey - Method domain.SearchMethod - Value interface{} -} - -type MessageTextSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*MessageTextView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/model/mfa_view.go b/internal/iam/model/mfa_view.go deleted file mode 100644 index 59f3dbc3cb..0000000000 --- a/internal/iam/model/mfa_view.go +++ /dev/null @@ -1,47 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" -) - -type SecondFactorsSearchRequest struct { - Queries []*MFASearchQuery -} - -type MultiFactorsSearchRequest struct { - Offset uint64 - Limit uint64 - Asc bool - Queries []*MFASearchQuery -} - -type MFASearchQuery struct { - Key MFASearchKey - Method domain.SearchMethod - Value interface{} -} - -type MFASearchKey int32 - -const ( - MFASearchKeyUnspecified MFASearchKey = iota - MFASearchKeyAggregateID -) - -type SecondFactorsSearchResponse struct { - TotalResult uint64 - Result []domain.SecondFactorType -} - -type MultiFactorsSearchResponse struct { - TotalResult uint64 - Result []domain.MultiFactorType -} - -func (r *SecondFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) { - r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID}) -} - -func (r *MultiFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) { - r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID}) -} diff --git a/internal/iam/model/password_age_policy.go b/internal/iam/model/password_age_policy.go deleted file mode 100644 index 70bc96e0f8..0000000000 --- a/internal/iam/model/password_age_policy.go +++ /dev/null @@ -1,13 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type PasswordAgePolicy struct { - models.ObjectRoot - - State PolicyState - MaxAgeDays uint64 - ExpireWarnDays uint64 -} diff --git a/internal/iam/model/password_age_policy_view.go b/internal/iam/model/password_age_policy_view.go deleted file mode 100644 index 9d9b36dc86..0000000000 --- a/internal/iam/model/password_age_policy_view.go +++ /dev/null @@ -1,48 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" -) - -type PasswordAgePolicyView struct { - AggregateID string - MaxAgeDays uint64 - ExpireWarnDays uint64 - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type PasswordAgePolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn PasswordAgePolicySearchKey - Asc bool - Queries []*PasswordAgePolicySearchQuery -} - -type PasswordAgePolicySearchKey int32 - -const ( - PasswordAgePolicySearchKeyUnspecified PasswordAgePolicySearchKey = iota - PasswordAgePolicySearchKeyAggregateID -) - -type PasswordAgePolicySearchQuery struct { - Key PasswordAgePolicySearchKey - Method domain.SearchMethod - Value interface{} -} - -type PasswordAgePolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*PasswordAgePolicyView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/model/password_complexity_policy.go b/internal/iam/model/password_complexity_policy.go deleted file mode 100644 index 90081b9ccd..0000000000 --- a/internal/iam/model/password_complexity_policy.go +++ /dev/null @@ -1,58 +0,0 @@ -package model - -import ( - "regexp" - - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/zerrors" -) - -var ( - hasStringLowerCase = regexp.MustCompile(`[a-z]`).MatchString - hasStringUpperCase = regexp.MustCompile(`[A-Z]`).MatchString - hasNumber = regexp.MustCompile(`[0-9]`).MatchString - hasSymbol = regexp.MustCompile(`[^A-Za-z0-9]`).MatchString -) - -type PasswordComplexityPolicy struct { - models.ObjectRoot - - State PolicyState - MinLength uint64 - HasLowercase bool - HasUppercase bool - HasNumber bool - HasSymbol bool - - Default bool -} - -func (p *PasswordComplexityPolicy) IsValid() error { - if p.MinLength == 0 || p.MinLength > 72 { - return zerrors.ThrowInvalidArgument(nil, "MODEL-Lsp0e", "Errors.User.PasswordComplexityPolicy.MinLengthNotAllowed") - } - return nil -} - -func (p *PasswordComplexityPolicy) Check(password string) error { - if p.MinLength != 0 && uint64(len(password)) < p.MinLength { - return zerrors.ThrowInvalidArgument(nil, "MODEL-HuJf6", "Errors.User.PasswordComplexityPolicy.MinLength") - } - - if p.HasLowercase && !hasStringLowerCase(password) { - return zerrors.ThrowInvalidArgument(nil, "MODEL-co3Xw", "Errors.User.PasswordComplexityPolicy.HasLower") - } - - if p.HasUppercase && !hasStringUpperCase(password) { - return zerrors.ThrowInvalidArgument(nil, "MODEL-VoaRj", "Errors.User.PasswordComplexityPolicy.HasUpper") - } - - if p.HasNumber && !hasNumber(password) { - return zerrors.ThrowInvalidArgument(nil, "MODEL-ZBv4H", "Errors.User.PasswordComplexityPolicy.HasNumber") - } - - if p.HasSymbol && !hasSymbol(password) { - return zerrors.ThrowInvalidArgument(nil, "MODEL-ZDLwA", "Errors.User.PasswordComplexityPolicy.HasSymbol") - } - return nil -} diff --git a/internal/iam/model/password_complexity_policy_view.go b/internal/iam/model/password_complexity_policy_view.go index 6f73bc41f8..7cc1d35017 100644 --- a/internal/iam/model/password_complexity_policy_view.go +++ b/internal/iam/model/password_complexity_policy_view.go @@ -2,8 +2,6 @@ package model import ( "time" - - "github.com/zitadel/zitadel/internal/domain" ) type PasswordComplexityPolicyView struct { @@ -19,33 +17,3 @@ type PasswordComplexityPolicyView struct { ChangeDate time.Time Sequence uint64 } - -type PasswordComplexityPolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn PasswordComplexityPolicySearchKey - Asc bool - Queries []*PasswordComplexityPolicySearchQuery -} - -type PasswordComplexityPolicySearchKey int32 - -const ( - PasswordComplexityPolicySearchKeyUnspecified PasswordComplexityPolicySearchKey = iota - PasswordComplexityPolicySearchKeyAggregateID -) - -type PasswordComplexityPolicySearchQuery struct { - Key PasswordComplexityPolicySearchKey - Method domain.SearchMethod - Value interface{} -} - -type PasswordComplexityPolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*PasswordComplexityPolicyView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/model/password_lockout_policy.go b/internal/iam/model/password_lockout_policy.go deleted file mode 100644 index 6cf8f6b27e..0000000000 --- a/internal/iam/model/password_lockout_policy.go +++ /dev/null @@ -1,13 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type LockoutPolicy struct { - models.ObjectRoot - - State PolicyState - MaxPasswordAttempts uint64 - ShowLockOutFailures bool -} diff --git a/internal/iam/model/password_lockout_policy_view.go b/internal/iam/model/password_lockout_policy_view.go deleted file mode 100644 index fd3f94ab96..0000000000 --- a/internal/iam/model/password_lockout_policy_view.go +++ /dev/null @@ -1,48 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" -) - -type LockoutPolicyView struct { - AggregateID string - MaxPasswordAttempts uint64 - ShowLockOutFailures bool - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type LockoutPolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn LockoutPolicySearchKey - Asc bool - Queries []*LockoutPolicySearchQuery -} - -type LockoutPolicySearchKey int32 - -const ( - LockoutPolicySearchKeyUnspecified LockoutPolicySearchKey = iota - LockoutPolicySearchKeyAggregateID -) - -type LockoutPolicySearchQuery struct { - Key LockoutPolicySearchKey - Method domain.SearchMethod - Value interface{} -} - -type LockoutPolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*LockoutPolicyView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/model/privacy_policy_view.go b/internal/iam/model/privacy_policy_view.go deleted file mode 100644 index 6d40dd3937..0000000000 --- a/internal/iam/model/privacy_policy_view.go +++ /dev/null @@ -1,49 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" -) - -type PrivacyPolicyView struct { - AggregateID string - TOSLink string - PrivacyLink string - SupportEmail string - Default bool - - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type PrivacyPolicySearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn PrivacyPolicySearchKey - Asc bool - Queries []*PrivacyPolicySearchQuery -} - -type PrivacyPolicySearchKey int32 - -const ( - PrivacyPolicySearchKeyUnspecified PrivacyPolicySearchKey = iota - PrivacyPolicySearchKeyAggregateID -) - -type PrivacyPolicySearchQuery struct { - Key PrivacyPolicySearchKey - Method domain.SearchMethod - Value interface{} -} - -type PrivacyPolicySearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*PrivacyPolicyView - Sequence uint64 - Timestamp time.Time -} diff --git a/internal/iam/repository/eventsourcing/model/iam_member.go b/internal/iam/repository/eventsourcing/model/iam_member.go deleted file mode 100644 index 2f9c664595..0000000000 --- a/internal/iam/repository/eventsourcing/model/iam_member.go +++ /dev/null @@ -1,23 +0,0 @@ -package model - -import ( - "encoding/json" - - "github.com/zitadel/logging" - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type IAMMember struct { - es_models.ObjectRoot - UserID string `json:"userId,omitempty"` - Roles []string `json:"roles,omitempty"` -} - -func (m *IAMMember) SetData(event *es_models.Event) error { - m.ObjectRoot.AppendEvent(event) - if err := json.Unmarshal(event.Data, m); err != nil { - logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data") - return err - } - return nil -} diff --git a/internal/iam/repository/eventsourcing/model/org_iam_policy.go b/internal/iam/repository/eventsourcing/model/org_iam_policy.go index d56b4ee7a5..e7cd9ed463 100644 --- a/internal/iam/repository/eventsourcing/model/org_iam_policy.go +++ b/internal/iam/repository/eventsourcing/model/org_iam_policy.go @@ -22,15 +22,6 @@ func DomainPolicyToModel(policy *DomainPolicy) *iam_model.DomainPolicy { } } -func (p *DomainPolicy) Changes(changed *DomainPolicy) map[string]interface{} { - changes := make(map[string]interface{}, 1) - - if p.UserLoginMustBeDomain != changed.UserLoginMustBeDomain { - changes["userLoginMustBeDomain"] = changed.UserLoginMustBeDomain - } - return changes -} - func (p *DomainPolicy) SetData(event eventstore.Event) error { err := event.Unmarshal(p) if err != nil { diff --git a/internal/iam/repository/eventsourcing/model/org_iam_policy_test.go b/internal/iam/repository/eventsourcing/model/org_iam_policy_test.go deleted file mode 100644 index 42148b1e6f..0000000000 --- a/internal/iam/repository/eventsourcing/model/org_iam_policy_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package model - -import ( - "testing" -) - -func TestOrgIAMPolicyChanges(t *testing.T) { - type args struct { - existing *DomainPolicy - new *DomainPolicy - } - type res struct { - changesLen int - } - tests := []struct { - name string - args args - res res - }{ - { - name: "org iam policy all attributes change", - args: args{ - existing: &DomainPolicy{UserLoginMustBeDomain: true}, - new: &DomainPolicy{UserLoginMustBeDomain: false}, - }, - res: res{ - changesLen: 1, - }, - }, - { - name: "no changes", - args: args{ - existing: &DomainPolicy{UserLoginMustBeDomain: true}, - new: &DomainPolicy{UserLoginMustBeDomain: true}, - }, - res: res{ - changesLen: 0, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - changes := tt.args.existing.Changes(tt.args.new) - if len(changes) != tt.res.changesLen { - t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes)) - } - }) - } -} diff --git a/internal/iam/repository/view/idp_provider_view.go b/internal/iam/repository/view/idp_provider_view.go deleted file mode 100644 index 3b5d9b2c2c..0000000000 --- a/internal/iam/repository/view/idp_provider_view.go +++ /dev/null @@ -1,143 +0,0 @@ -package view - -import ( - "github.com/jinzhu/gorm" - - "github.com/zitadel/zitadel/internal/domain" - iam_model "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/iam/repository/view/model" - "github.com/zitadel/zitadel/internal/view/repository" - "github.com/zitadel/zitadel/internal/zerrors" -) - -func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) (*model.IDPProviderView, error) { - policy := new(model.IDPProviderView) - aggIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals} - idpConfigIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyIdpConfigID, Value: idpConfigID, Method: domain.SearchMethodEquals} - instanceIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - ownerRemovedQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, policy) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Skvi8", "Errors.IAM.LoginPolicy.IDP.NotExisting") - } - return policy, err -} - -func IDPProvidersByIdpConfigID(db *gorm.DB, table, idpConfigID, instanceID string) ([]*model.IDPProviderView, error) { - providers := make([]*model.IDPProviderView, 0) - queries := []*iam_model.IDPProviderSearchQuery{ - { - Key: iam_model.IDPProviderSearchKeyIdpConfigID, - Value: idpConfigID, - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPProviderSearchKeyInstanceID, - Value: instanceID, - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPProviderSearchKeyOwnerRemoved, - Value: false, - Method: domain.SearchMethodEquals, - }, - } - query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries}) - _, err := query(db, &providers) - if err != nil { - return nil, err - } - return providers, nil -} - -func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID, instanceID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) { - providers := make([]*model.IDPProviderView, 0) - queries := []*iam_model.IDPProviderSearchQuery{ - { - Key: iam_model.IDPProviderSearchKeyAggregateID, - Value: aggregateID, - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPProviderSearchKeyState, - Value: int(idpConfigState), - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPProviderSearchKeyInstanceID, - Value: instanceID, - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPProviderSearchKeyOwnerRemoved, - Value: false, - Method: domain.SearchMethodEquals, - }, - } - query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries}) - _, err := query(db, &providers) - if err != nil { - return nil, err - } - return providers, nil -} - -func SearchIDPProviders(db *gorm.DB, table string, req *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) { - providers := make([]*model.IDPProviderView, 0) - query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) - count, err := query(db, &providers) - if err != nil { - return nil, 0, err - } - return providers, count, nil -} - -func PutIDPProvider(db *gorm.DB, table string, provider *model.IDPProviderView) error { - save := repository.PrepareSave(table) - return save(db, provider) -} - -func PutIDPProviders(db *gorm.DB, table string, providers ...*model.IDPProviderView) error { - save := repository.PrepareBulkSave(table) - p := make([]interface{}, len(providers)) - for i, provider := range providers { - p[i] = provider - } - return save(db, p...) -} - -func DeleteIDPProvider(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID}, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyIdpConfigID), Value: idpConfigID}, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID}, - ) - return delete(db) -} - -func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID}, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID}, - ) - return delete(db) -} - -func DeleteInstanceIDPProviders(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, - model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), - instanceID, - ) - return delete(db) -} - -func UpdateOrgOwnerRemovedIDPProviders(db *gorm.DB, table, instanceID, aggID string) error { - update := repository.PrepareUpdateByKeys(table, - model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyOwnerRemoved), - true, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID}, - repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggID}, - ) - return update(db) -} diff --git a/internal/iam/repository/view/idp_view.go b/internal/iam/repository/view/idp_view.go deleted file mode 100644 index ad2cac2bba..0000000000 --- a/internal/iam/repository/view/idp_view.go +++ /dev/null @@ -1,88 +0,0 @@ -package view - -import ( - "github.com/jinzhu/gorm" - - "github.com/zitadel/zitadel/internal/domain" - iam_model "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/iam/repository/view/model" - "github.com/zitadel/zitadel/internal/view/repository" - "github.com/zitadel/zitadel/internal/zerrors" -) - -func IDPByID(db *gorm.DB, table, idpID, instanceID string) (*model.IDPConfigView, error) { - idp := new(model.IDPConfigView) - idpIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyIdpConfigID, Value: idpID, Method: domain.SearchMethodEquals} - instanceIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - ownerRemovedQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, idpIDQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, idp) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IDP.NotExisting") - } - return idp, err -} - -func GetIDPConfigsByAggregateID(db *gorm.DB, table string, aggregateID, instanceID string) ([]*model.IDPConfigView, error) { - idps := make([]*model.IDPConfigView, 0) - queries := []*iam_model.IDPConfigSearchQuery{ - { - Key: iam_model.IDPConfigSearchKeyAggregateID, - Value: aggregateID, - Method: domain.SearchMethodEquals, - }, { - Key: iam_model.IDPConfigSearchKeyInstanceID, - Value: instanceID, - Method: domain.SearchMethodEquals, - }, - { - Key: iam_model.IDPConfigSearchKeyOwnerRemoved, - Value: false, - Method: domain.SearchMethodEquals, - }, - } - query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Queries: queries}) - _, err := query(db, &idps) - if err != nil { - return nil, err - } - return idps, nil -} - -func SearchIDPs(db *gorm.DB, table string, req *iam_model.IDPConfigSearchRequest) ([]*model.IDPConfigView, uint64, error) { - idps := make([]*model.IDPConfigView, 0) - query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) - count, err := query(db, &idps) - if err != nil { - return nil, 0, err - } - return idps, count, nil -} - -func PutIDP(db *gorm.DB, table string, idp *model.IDPConfigView) error { - save := repository.PrepareSave(table) - return save(db, idp) -} - -func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID}, - repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID}, - ) - return delete(db) -} - -func UpdateOrgOwnerRemovedIDPs(db *gorm.DB, table, instanceID, aggID string) error { - update := repository.PrepareUpdateByKeys(table, - model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyOwnerRemoved), - true, - repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), Value: instanceID}, - repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyAggregateID), Value: aggID}, - ) - return update(db) -} - -func DeleteInstanceIDPs(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID) - return delete(db) -} diff --git a/internal/iam/repository/view/model/idp_config.go b/internal/iam/repository/view/model/idp_config.go deleted file mode 100644 index 529068e244..0000000000 --- a/internal/iam/repository/view/model/idp_config.go +++ /dev/null @@ -1,123 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/crypto" - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - IDPConfigKeyIdpConfigID = "idp_config_id" - IDPConfigKeyAggregateID = "aggregate_id" - IDPConfigKeyName = "name" - IDPConfigKeyProviderType = "idp_provider_type" - IDPConfigKeyInstanceID = "instance_id" - IDPConfigKeyOwnerRemoved = "owner_removed" -) - -type IDPConfigView struct { - IDPConfigID string `json:"idpConfigId" gorm:"column:idp_config_id;primary_key"` - AggregateID string `json:"-" gorm:"column:aggregate_id"` - Name string `json:"name" gorm:"column:name"` - StylingType int32 `json:"stylingType" gorm:"column:styling_type"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - IDPState int32 `json:"-" gorm:"column:idp_state"` - IDPProviderType int32 `json:"-" gorm:"column:idp_provider_type"` - AutoRegister bool `json:"autoRegister" gorm:"column:auto_register"` - - IsOIDC bool `json:"-" gorm:"column:is_oidc"` - OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"` - OIDCClientSecret *crypto.CryptoValue `json:"clientSecret" gorm:"column:oidc_client_secret"` - OIDCIssuer string `json:"issuer" gorm:"column:oidc_issuer"` - OIDCScopes database.TextArray[string] `json:"scopes" gorm:"column:oidc_scopes"` - OIDCIDPDisplayNameMapping int32 `json:"idpDisplayNameMapping" gorm:"column:oidc_idp_display_name_mapping"` - OIDCUsernameMapping int32 `json:"usernameMapping" gorm:"column:oidc_idp_username_mapping"` - OAuthAuthorizationEndpoint string `json:"authorizationEndpoint" gorm:"column:oauth_authorization_endpoint"` - OAuthTokenEndpoint string `json:"tokenEndpoint" gorm:"column:oauth_token_endpoint"` - JWTEndpoint string `json:"jwtEndpoint" gorm:"jwt_endpoint"` - JWTKeysEndpoint string `json:"keysEndpoint" gorm:"jwt_keys_endpoint"` - JWTHeaderName string `json:"headerName" gorm:"jwt_header_name"` - - Sequence uint64 `json:"-" gorm:"column:sequence"` - InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"` -} - -func IDPConfigViewToModel(idp *IDPConfigView) *model.IDPConfigView { - view := &model.IDPConfigView{ - IDPConfigID: idp.IDPConfigID, - AggregateID: idp.AggregateID, - State: model.IDPConfigState(idp.IDPState), - Name: idp.Name, - StylingType: model.IDPStylingType(idp.StylingType), - AutoRegister: idp.AutoRegister, - Sequence: idp.Sequence, - CreationDate: idp.CreationDate, - ChangeDate: idp.ChangeDate, - IDPProviderType: model.IDPProviderType(idp.IDPProviderType), - IsOIDC: idp.IsOIDC, - OIDCClientID: idp.OIDCClientID, - OIDCClientSecret: idp.OIDCClientSecret, - OIDCScopes: idp.OIDCScopes, - OIDCIDPDisplayNameMapping: model.OIDCMappingField(idp.OIDCIDPDisplayNameMapping), - OIDCUsernameMapping: model.OIDCMappingField(idp.OIDCUsernameMapping), - OAuthAuthorizationEndpoint: idp.OAuthAuthorizationEndpoint, - OAuthTokenEndpoint: idp.OAuthTokenEndpoint, - } - if idp.IsOIDC { - view.OIDCIssuer = idp.OIDCIssuer - return view - } - view.JWTEndpoint = idp.JWTEndpoint - view.JWTIssuer = idp.OIDCIssuer - view.JWTKeysEndpoint = idp.JWTKeysEndpoint - view.JWTHeaderName = idp.JWTHeaderName - return view -} - -func (i *IDPConfigView) AppendEvent(providerType model.IDPProviderType, event eventstore.Event) (err error) { - i.Sequence = event.Sequence() - i.ChangeDate = event.CreatedAt() - switch event.Type() { - case instance.IDPConfigAddedEventType, org.IDPConfigAddedEventType: - i.setRootData(event) - i.CreationDate = event.CreatedAt() - i.IDPProviderType = int32(providerType) - err = i.SetData(event) - case instance.IDPOIDCConfigAddedEventType, org.IDPOIDCConfigAddedEventType: - i.IsOIDC = true - err = i.SetData(event) - case instance.IDPOIDCConfigChangedEventType, org.IDPOIDCConfigChangedEventType, - instance.IDPConfigChangedEventType, org.IDPConfigChangedEventType, - org.IDPJWTConfigAddedEventType, instance.IDPJWTConfigAddedEventType, - org.IDPJWTConfigChangedEventType, instance.IDPJWTConfigChangedEventType: - err = i.SetData(event) - case instance.IDPConfigDeactivatedEventType, org.IDPConfigDeactivatedEventType: - i.IDPState = int32(model.IDPConfigStateInactive) - case instance.IDPConfigReactivatedEventType, org.IDPConfigReactivatedEventType: - i.IDPState = int32(model.IDPConfigStateActive) - } - return err -} - -func (r *IDPConfigView) setRootData(event eventstore.Event) { - r.AggregateID = event.Aggregate().ID - r.InstanceID = event.Aggregate().InstanceID -} - -func (r *IDPConfigView) SetData(event eventstore.Event) error { - err := event.Unmarshal(r) - if err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data") - } - return nil -} diff --git a/internal/iam/repository/view/model/idp_config_query.go b/internal/iam/repository/view/model/idp_config_query.go deleted file mode 100644 index 5f07ecfcee..0000000000 --- a/internal/iam/repository/view/model/idp_config_query.go +++ /dev/null @@ -1,69 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - iam_model "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type IDPConfigSearchRequest iam_model.IDPConfigSearchRequest -type IDPConfigSearchQuery iam_model.IDPConfigSearchQuery -type IDPConfigSearchKey iam_model.IDPConfigSearchKey - -func (req IDPConfigSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req IDPConfigSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req IDPConfigSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == iam_model.IDPConfigSearchKeyUnspecified { - return nil - } - return IDPConfigSearchKey(req.SortingColumn) -} - -func (req IDPConfigSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req IDPConfigSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = IDPConfigSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req IDPConfigSearchQuery) GetKey() repository.ColumnKey { - return IDPConfigSearchKey(req.Key) -} - -func (req IDPConfigSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req IDPConfigSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key IDPConfigSearchKey) ToColumnName() string { - switch iam_model.IDPConfigSearchKey(key) { - case iam_model.IDPConfigSearchKeyAggregateID: - return IDPConfigKeyAggregateID - case iam_model.IDPConfigSearchKeyIdpConfigID: - return IDPConfigKeyIdpConfigID - case iam_model.IDPConfigSearchKeyName: - return IDPConfigKeyName - case iam_model.IDPConfigSearchKeyIdpProviderType: - return IDPConfigKeyProviderType - case iam_model.IDPConfigSearchKeyInstanceID: - return IDPConfigKeyInstanceID - case iam_model.IDPConfigSearchKeyOwnerRemoved: - return IDPConfigKeyOwnerRemoved - default: - return "" - } -} diff --git a/internal/iam/repository/view/model/idp_provider.go b/internal/iam/repository/view/model/idp_provider.go deleted file mode 100644 index 779df2426e..0000000000 --- a/internal/iam/repository/view/model/idp_provider.go +++ /dev/null @@ -1,87 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - IDPProviderKeyAggregateID = "aggregate_id" - IDPProviderKeyIdpConfigID = "idp_config_id" - IDPProviderKeyState = "idp_state" - IDPProviderKeyInstanceID = "instance_id" - IDPProviderKeyOwnerRemoved = "owner_removed" -) - -type IDPProviderView struct { - AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"` - IDPConfigID string `json:"idpConfigID" gorm:"column:idp_config_id;primary_key"` - - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - - Name string `json:"-" gorm:"column:name"` - StylingType int32 `json:"-" gorm:"column:styling_type"` - IDPConfigType int32 `json:"-" gorm:"column:idp_config_type"` - IDPProviderType int32 `json:"idpProviderType" gorm:"column:idp_provider_type"` - IDPState int32 `json:"-" gorm:"column:idp_state"` - - Sequence uint64 `json:"-" gorm:"column:sequence"` - InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"` -} - -func IDPProviderViewToModel(provider *IDPProviderView) *model.IDPProviderView { - return &model.IDPProviderView{ - AggregateID: provider.AggregateID, - Sequence: provider.Sequence, - CreationDate: provider.CreationDate, - ChangeDate: provider.ChangeDate, - Name: provider.Name, - StylingType: model.IDPStylingType(provider.StylingType), - IDPConfigID: provider.IDPConfigID, - IDPConfigType: model.IdpConfigType(provider.IDPConfigType), - IDPProviderType: model.IDPProviderType(provider.IDPProviderType), - IDPState: model.IDPConfigState(provider.IDPState), - } -} - -func IDPProviderViewsToModel(providers []*IDPProviderView) []*model.IDPProviderView { - result := make([]*model.IDPProviderView, len(providers)) - for i, r := range providers { - result[i] = IDPProviderViewToModel(r) - } - return result -} - -func (i *IDPProviderView) AppendEvent(event eventstore.Event) (err error) { - i.Sequence = event.Sequence() - i.ChangeDate = event.CreatedAt() - switch event.Type() { - case instance.LoginPolicyIDPProviderAddedEventType, - org.LoginPolicyIDPProviderAddedEventType: - i.setRootData(event) - i.CreationDate = event.CreatedAt() - err = i.SetData(event) - } - return err -} - -func (r *IDPProviderView) setRootData(event eventstore.Event) { - r.AggregateID = event.Aggregate().ID - r.InstanceID = event.Aggregate().InstanceID -} - -func (r *IDPProviderView) SetData(event eventstore.Event) error { - if err := event.Unmarshal(r); err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data") - } - return nil -} diff --git a/internal/iam/repository/view/model/idp_provider_query.go b/internal/iam/repository/view/model/idp_provider_query.go deleted file mode 100644 index 9685507c1b..0000000000 --- a/internal/iam/repository/view/model/idp_provider_query.go +++ /dev/null @@ -1,67 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - iam_model "github.com/zitadel/zitadel/internal/iam/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type IDPProviderSearchRequest iam_model.IDPProviderSearchRequest -type IDPProviderSearchQuery iam_model.IDPProviderSearchQuery -type IDPProviderSearchKey iam_model.IDPProviderSearchKey - -func (req IDPProviderSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req IDPProviderSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req IDPProviderSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == iam_model.IDPProviderSearchKeyUnspecified { - return nil - } - return IDPProviderSearchKey(req.SortingColumn) -} - -func (req IDPProviderSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req IDPProviderSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = IDPProviderSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req IDPProviderSearchQuery) GetKey() repository.ColumnKey { - return IDPProviderSearchKey(req.Key) -} - -func (req IDPProviderSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req IDPProviderSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key IDPProviderSearchKey) ToColumnName() string { - switch iam_model.IDPProviderSearchKey(key) { - case iam_model.IDPProviderSearchKeyAggregateID: - return IDPProviderKeyAggregateID - case iam_model.IDPProviderSearchKeyIdpConfigID: - return IDPProviderKeyIdpConfigID - case iam_model.IDPProviderSearchKeyState: - return IDPProviderKeyState - case iam_model.IDPProviderSearchKeyInstanceID: - return IDPProviderKeyInstanceID - case iam_model.IDPProviderSearchKeyOwnerRemoved: - return IDPProviderKeyOwnerRemoved - default: - return "" - } -} diff --git a/internal/iam/repository/view/model/label_policy_query.go b/internal/iam/repository/view/model/label_policy_query.go index 1c21d39be1..4f8f2d069a 100644 --- a/internal/iam/repository/view/model/label_policy_query.go +++ b/internal/iam/repository/view/model/label_policy_query.go @@ -6,37 +6,9 @@ import ( "github.com/zitadel/zitadel/internal/view/repository" ) -type LabelPolicySearchRequest iam_model.LabelPolicySearchRequest type LabelPolicySearchQuery iam_model.LabelPolicySearchQuery type LabelPolicySearchKey iam_model.LabelPolicySearchKey -func (req LabelPolicySearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req LabelPolicySearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req LabelPolicySearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == iam_model.LabelPolicySearchKeyUnspecified { - return nil - } - return LabelPolicySearchKey(req.SortingColumn) -} - -func (req LabelPolicySearchRequest) GetAsc() bool { - return req.Asc -} - -func (req LabelPolicySearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = LabelPolicySearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - func (req LabelPolicySearchQuery) GetKey() repository.ColumnKey { return LabelPolicySearchKey(req.Key) } diff --git a/internal/iam/repository/view/model/password_complexity_policy.go b/internal/iam/repository/view/model/password_complexity_policy.go index 80b2b57b22..3255b13079 100644 --- a/internal/iam/repository/view/model/password_complexity_policy.go +++ b/internal/iam/repository/view/model/password_complexity_policy.go @@ -1,38 +1,10 @@ package model import ( - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/iam/model" "github.com/zitadel/zitadel/internal/query" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/zerrors" ) -const ( - PasswordComplexityKeyAggregateID = "aggregate_id" -) - -type PasswordComplexityPolicyView struct { - AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - State int32 `json:"-" gorm:"column:complexity_policy_state"` - - MinLength uint64 `json:"minLength" gorm:"column:min_length"` - HasLowercase bool `json:"hasLowercase" gorm:"column:has_lowercase"` - HasUppercase bool `json:"hasUppercase" gorm:"column:has_uppercase"` - HasSymbol bool `json:"hasSymbol" gorm:"column:has_symbol"` - HasNumber bool `json:"hasNumber" gorm:"column:has_number"` - Default bool `json:"-" gorm:"-"` - - Sequence uint64 `json:"-" gorm:"column:sequence"` -} - func PasswordComplexityViewToModel(policy *query.PasswordComplexityPolicy) *model.PasswordComplexityPolicyView { return &model.PasswordComplexityPolicyView{ AggregateID: policy.ID, @@ -47,31 +19,3 @@ func PasswordComplexityViewToModel(policy *query.PasswordComplexityPolicy) *mode Default: policy.IsDefault, } } - -func (i *PasswordComplexityPolicyView) AppendEvent(event eventstore.Event) (err error) { - i.Sequence = event.Sequence() - i.ChangeDate = event.CreatedAt() - switch event.Type() { - case instance.PasswordComplexityPolicyAddedEventType, - org.PasswordComplexityPolicyAddedEventType: - i.setRootData(event) - i.CreationDate = event.CreatedAt() - err = i.SetData(event) - case instance.PasswordComplexityPolicyChangedEventType, - org.PasswordComplexityPolicyChangedEventType: - err = i.SetData(event) - } - return err -} - -func (r *PasswordComplexityPolicyView) setRootData(event eventstore.Event) { - r.AggregateID = event.Aggregate().ID -} - -func (r *PasswordComplexityPolicyView) SetData(event eventstore.Event) error { - if err := event.Unmarshal(r); err != nil { - logging.Log("EVEN-Dmi9g").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data") - } - return nil -} diff --git a/internal/integration/oidc.go b/internal/integration/oidc.go index aaf3ff1e31..16c4c90ae5 100644 --- a/internal/integration/oidc.go +++ b/internal/integration/oidc.go @@ -23,7 +23,7 @@ import ( "github.com/zitadel/zitadel/pkg/grpc/user" ) -func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, appType app.OIDCAppType, authMethod app.OIDCAuthMethodType) (*management.AddOIDCAppResponse, error) { +func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, appType app.OIDCAppType, authMethod app.OIDCAuthMethodType, devMode bool) (*management.AddOIDCAppResponse, error) { return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{ ProjectId: projectID, Name: fmt.Sprintf("app-%d", time.Now().UnixNano()), @@ -34,7 +34,7 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire AuthMethodType: authMethod, PostLogoutRedirectUris: []string{logoutRedirectURI}, Version: app.OIDCVersion_OIDC_VERSION_1_0, - DevMode: false, + DevMode: devMode, AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT, AccessTokenRoleAssertion: false, IdTokenRoleAssertion: false, @@ -45,16 +45,16 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire }) } -func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) { - return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE) +func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, devMode bool) (*management.AddOIDCAppResponse, error) { + return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, devMode) } func (s *Tester) CreateOIDCWebClientBasic(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) { - return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_BASIC) + return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_BASIC, false) } func (s *Tester) CreateOIDCWebClientJWT(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (client *management.AddOIDCAppResponse, keyData []byte, err error) { - client, err = s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT) + client, err = s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT, false) if err != nil { return nil, nil, err } @@ -71,7 +71,7 @@ func (s *Tester) CreateOIDCWebClientJWT(ctx context.Context, redirectURI, logout } func (s *Tester) CreateOIDCInactivateClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) { - client, err := s.CreateOIDCNativeClient(ctx, redirectURI, logoutRedirectURI, projectID) + client, err := s.CreateOIDCNativeClient(ctx, redirectURI, logoutRedirectURI, projectID, false) if err != nil { return nil, err } @@ -119,7 +119,7 @@ func (s *Tester) CreateProject(ctx context.Context) (*management.AddProjectRespo }) } -func (s *Tester) CreateAPIClient(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) { +func (s *Tester) CreateAPIClientJWT(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) { return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{ ProjectId: projectID, Name: fmt.Sprintf("api-%d", time.Now().UnixNano()), @@ -127,6 +127,14 @@ func (s *Tester) CreateAPIClient(ctx context.Context, projectID string) (*manage }) } +func (s *Tester) CreateAPIClientBasic(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) { + return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{ + ProjectId: projectID, + Name: fmt.Sprintf("api-%d", time.Now().UnixNano()), + AuthMethodType: app.APIAuthMethodType_API_AUTH_METHOD_TYPE_BASIC, + }) +} + const CodeVerifier = "codeVerifier" func (s *Tester) CreateOIDCAuthRequest(ctx context.Context, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) { @@ -207,7 +215,7 @@ func (c *loginRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) return c.RoundTripper.RoundTrip(req) } -func (s *Tester) CreateResourceServer(ctx context.Context, keyFileData []byte) (rs.ResourceServer, error) { +func (s *Tester) CreateResourceServerJWTProfile(ctx context.Context, keyFileData []byte) (rs.ResourceServer, error) { keyFile, err := client.ConfigFromKeyFileData(keyFileData) if err != nil { return nil, err @@ -215,6 +223,10 @@ func (s *Tester) CreateResourceServer(ctx context.Context, keyFileData []byte) ( return rs.NewResourceServerJWTProfile(ctx, s.OIDCIssuer(), keyFile.ClientID, keyFile.KeyID, []byte(keyFile.Key)) } +func (s *Tester) CreateResourceServerClientCredentials(ctx context.Context, clientID, clientSecret string) (rs.ResourceServer, error) { + return rs.NewResourceServerClientCredentials(ctx, s.OIDCIssuer(), clientID, clientSecret) +} + func GetRequest(url string, headers map[string]string) (*http.Request, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { diff --git a/internal/org/model/domain.go b/internal/org/model/domain.go index c1d951b841..88c3a8b028 100644 --- a/internal/org/model/domain.go +++ b/internal/org/model/domain.go @@ -1,7 +1,6 @@ package model import ( - http_util "github.com/zitadel/zitadel/internal/api/http" "github.com/zitadel/zitadel/internal/crypto" es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" ) @@ -22,35 +21,3 @@ const ( OrgDomainValidationTypeHTTP OrgDomainValidationTypeDNS ) - -func (t OrgDomainValidationType) CheckType() (http_util.CheckType, bool) { - switch t { - case OrgDomainValidationTypeHTTP: - return http_util.CheckTypeHTTP, true - case OrgDomainValidationTypeDNS: - return http_util.CheckTypeDNS, true - default: - return -1, false - } -} - -func (t OrgDomainValidationType) IsDNS() bool { - return t == OrgDomainValidationTypeDNS -} - -func NewOrgDomain(orgID, domain string) *OrgDomain { - return &OrgDomain{ObjectRoot: es_models.ObjectRoot{AggregateID: orgID}, Domain: domain} -} - -func (domain *OrgDomain) IsValid() bool { - return domain.AggregateID != "" && domain.Domain != "" -} - -func (domain *OrgDomain) GenerateVerificationCode(codeGenerator crypto.Generator) (string, error) { - validationCodeCrypto, validationCode, err := crypto.NewCode(codeGenerator) - if err != nil { - return "", err - } - domain.ValidationCode = validationCodeCrypto - return validationCode, nil -} diff --git a/internal/org/repository/eventsourcing/model/member.go b/internal/org/repository/eventsourcing/model/member.go deleted file mode 100644 index 328b9b45d6..0000000000 --- a/internal/org/repository/eventsourcing/model/member.go +++ /dev/null @@ -1,51 +0,0 @@ -package model - -import ( - "encoding/json" - "reflect" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type OrgMember struct { - es_models.ObjectRoot `json:"-"` - - UserID string `json:"userId,omitempty"` - Roles []string `json:"roles,omitempty"` -} - -func (m *OrgMember) AppendEvents(events ...*es_models.Event) error { - for _, event := range events { - err := m.AppendEvent(event) - if err != nil { - return err - } - } - return nil -} - -func (m *OrgMember) AppendEvent(event *es_models.Event) error { - m.ObjectRoot.AppendEvent(event) - - return m.SetData(event) -} - -func (m *OrgMember) SetData(event *es_models.Event) error { - err := json.Unmarshal(event.Data, m) - if err != nil { - return zerrors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data") - } - return nil -} - -func (m *OrgMember) Changes(updatedMember *OrgMember) map[string]interface{} { - changes := make(map[string]interface{}, 2) - - if !reflect.DeepEqual(m.Roles, updatedMember.Roles) { - changes["roles"] = updatedMember.Roles - changes["userId"] = m.UserID - } - - return changes -} diff --git a/internal/org/repository/eventsourcing/model/org.go b/internal/org/repository/eventsourcing/model/org.go index 4ff271fe21..98f47c2dbf 100644 --- a/internal/org/repository/eventsourcing/model/org.go +++ b/internal/org/repository/eventsourcing/model/org.go @@ -97,13 +97,3 @@ func (o *Org) SetData(event eventstore.Event) error { } return nil } - -func (o *Org) Changes(changed *Org) map[string]interface{} { - changes := make(map[string]interface{}, 2) - - if changed.Name != "" && changed.Name != o.Name { - changes["name"] = changed.Name - } - - return changes -} diff --git a/internal/org/repository/eventsourcing/model/org_test.go b/internal/org/repository/eventsourcing/model/org_test.go index af6cd96331..95085eb244 100644 --- a/internal/org/repository/eventsourcing/model/org_test.go +++ b/internal/org/repository/eventsourcing/model/org_test.go @@ -116,47 +116,3 @@ func TestAppendEvent(t *testing.T) { }) } } - -func TestChanges(t *testing.T) { - type args struct { - existingOrg *Org - newOrg *Org - } - type res struct { - changesLen int - } - tests := []struct { - name string - args args - res res - }{ - { - name: "org name changes", - args: args{ - existingOrg: &Org{Name: "Name"}, - newOrg: &Org{Name: "NameChanged"}, - }, - res: res{ - changesLen: 1, - }, - }, - { - name: "no changes", - args: args{ - existingOrg: &Org{Name: "Name"}, - newOrg: &Org{Name: "Name"}, - }, - res: res{ - changesLen: 0, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - changes := tt.args.existingOrg.Changes(tt.args.newOrg) - if len(changes) != tt.res.changesLen { - t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes)) - } - }) - } -} diff --git a/internal/project/model/api_config.go b/internal/project/model/api_config.go index e2854b4165..e2ae43f338 100644 --- a/internal/project/model/api_config.go +++ b/internal/project/model/api_config.go @@ -1,15 +1,8 @@ package model import ( - "fmt" - "strings" - - "github.com/zitadel/logging" - "github.com/zitadel/zitadel/internal/crypto" es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/id" - "github.com/zitadel/zitadel/internal/zerrors" ) type APIConfig struct { @@ -27,35 +20,3 @@ const ( APIAuthMethodTypeBasic APIAuthMethodType = iota APIAuthMethodTypePrivateKeyJWT ) - -func (c *APIConfig) IsValid() bool { - return true -} - -// ClientID random_number@projectname (eg. 495894098234@zitadel) -func (c *APIConfig) GenerateNewClientID(idGenerator id.Generator, project *Project) error { - rndID, err := idGenerator.Next() - if err != nil { - return err - } - - c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_")) - return nil -} - -func (c *APIConfig) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) { - if c.AuthMethodType == APIAuthMethodTypeBasic { - return c.GenerateNewClientSecret(generator) - } - return "", nil -} - -func (c *APIConfig) GenerateNewClientSecret(generator crypto.Generator) (string, error) { - cryptoValue, stringSecret, err := crypto.NewCode(generator) - if err != nil { - logging.Log("MODEL-ADvd2").OnError(err).Error("unable to create client secret") - return "", zerrors.ThrowInternal(err, "MODEL-dsvr43", "Errors.Project.CouldNotGenerateClientSecret") - } - c.ClientSecret = cryptoValue - return stringSecret, nil -} diff --git a/internal/project/model/application.go b/internal/project/model/application.go index f38263eb72..0816511eb4 100644 --- a/internal/project/model/application.go +++ b/internal/project/model/application.go @@ -32,22 +32,3 @@ const ( AppTypeSAML AppTypeAPI ) - -func (a *Application) IsValid(includeConfig bool) bool { - if a.Name == "" || a.AggregateID == "" { - return false - } - if !includeConfig { - return true - } - if a.Type == AppTypeOIDC && !a.OIDCConfig.IsValid() { - return false - } - if a.Type == AppTypeAPI && !a.APIConfig.IsValid() { - return false - } - if a.Type == AppTypeSAML && !a.SAMLConfig.IsValid() { - return false - } - return true -} diff --git a/internal/project/model/application_test.go b/internal/project/model/application_test.go deleted file mode 100644 index 0feabf0174..0000000000 --- a/internal/project/model/application_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package model - -import ( - "testing" - - "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -func TestApplicationValid(t *testing.T) { - type args struct { - app *Application - } - tests := []struct { - name string - args args - result bool - }{ - { - name: "valid oidc application: responsetype code", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode}, - }, - }, - }, - result: true, - }, - { - name: "invalid oidc application: responsetype code", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit}, - }, - }, - }, - result: false, - }, - { - name: "valid oidc application: responsetype id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit}, - }, - }, - }, - result: true, - }, - { - name: "invalid oidc application: responsetype id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode}, - }, - }, - }, - result: false, - }, - { - name: "valid oidc application: responsetype token_id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDTokenToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit}, - }, - }, - }, - result: true, - }, - { - name: "invalid oidc application: responsetype token_id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDTokenToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode}, - }, - }, - }, - result: false, - }, - { - name: "valid oidc application: responsetype code & id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit}, - }, - }, - }, - result: true, - }, - { - name: "valid oidc application: responsetype code & token_id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDTokenToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit}, - }, - }, - }, - result: true, - }, - { - name: "valid oidc application: responsetype code & id_token & token_id_token", - args: args{ - app: &Application{ - ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, - AppID: "AppID", - Name: "Name", - Type: AppTypeOIDC, - OIDCConfig: &OIDCConfig{ - ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken}, - GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit}, - }, - }, - }, - result: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := tt.args.app.IsValid(true) - if result != tt.result { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, result) - } - }) - } -} diff --git a/internal/project/model/oidc_config.go b/internal/project/model/oidc_config.go index dbcece15f7..50be6c318a 100644 --- a/internal/project/model/oidc_config.go +++ b/internal/project/model/oidc_config.go @@ -1,17 +1,11 @@ package model import ( - "fmt" - "strings" "time" - "github.com/zitadel/logging" - "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/id" - "github.com/zitadel/zitadel/internal/zerrors" ) type OIDCConfig struct { @@ -97,49 +91,6 @@ type Token struct { Scopes []string } -func (c *OIDCConfig) IsValid() bool { - grantTypes := c.getRequiredGrantTypes() - for _, grantType := range grantTypes { - ok := containsOIDCGrantType(c.GrantTypes, grantType) - if !ok { - return false - } - } - return true -} - -// ClientID random_number@projectname (eg. 495894098234@zitadel) -func (c *OIDCConfig) GenerateNewClientID(idGenerator id.Generator, project *Project) error { - rndID, err := idGenerator.Next() - if err != nil { - return err - } - - c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_")) - return nil -} - -func (c *OIDCConfig) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) { - if c.AuthMethodType == OIDCAuthMethodTypeBasic || c.AuthMethodType == OIDCAuthMethodTypePost { - return c.GenerateNewClientSecret(generator) - } - return "", nil -} - -func (c *OIDCConfig) GenerateNewClientSecret(generator crypto.Generator) (string, error) { - cryptoValue, stringSecret, err := crypto.NewCode(generator) - if err != nil { - logging.Log("MODEL-UpnTI").OnError(err).Error("unable to create client secret") - return "", zerrors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret") - } - c.ClientSecret = cryptoValue - return stringSecret, nil -} - -func (c *OIDCConfig) FillCompliance() { - c.Compliance = GetOIDCCompliance(c.OIDCVersion, c.ApplicationType, c.GrantTypes, c.ResponseTypes, c.AuthMethodType, c.RedirectUris) -} - func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTypes []OIDCGrantType, responseTypes []OIDCResponseType, authMethod OIDCAuthMethodType, redirectUris []string) *Compliance { switch version { case OIDCVersionV1: @@ -155,29 +106,3 @@ func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTy } return nil } - -func (c *OIDCConfig) getRequiredGrantTypes() []OIDCGrantType { - grantTypes := make([]OIDCGrantType, 0) - implicit := false - for _, r := range c.ResponseTypes { - switch r { - case OIDCResponseTypeCode: - grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode) - case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken: - if !implicit { - implicit = true - grantTypes = append(grantTypes, OIDCGrantTypeImplicit) - } - } - } - return grantTypes -} - -func containsOIDCGrantType(grantTypes []OIDCGrantType, grantType OIDCGrantType) bool { - for _, gt := range grantTypes { - if gt == grantType { - return true - } - } - return false -} diff --git a/internal/project/model/org_project_mapping_view.go b/internal/project/model/org_project_mapping_view.go deleted file mode 100644 index e744285533..0000000000 --- a/internal/project/model/org_project_mapping_view.go +++ /dev/null @@ -1,55 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - - "time" -) - -type OrgProjectMapping struct { - OrgID string - ProjectID string -} - -type OrgProjectMappingViewSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn OrgProjectMappingViewSearchKey - Asc bool - Queries []*OrgProjectMappingViewSearchQuery -} - -type OrgProjectMappingViewSearchKey int32 - -const ( - OrgProjectMappingSearchKeyUnspecified OrgProjectMappingViewSearchKey = iota - OrgProjectMappingSearchKeyProjectID - OrgProjectMappingSearchKeyOrgID - OrgProjectMappingSearchKeyProjectGrantID - OrgProjectMappingSearchKeyInstanceID - OrgProjectMappingSearchKeyOwnerRemoved -) - -type OrgProjectMappingViewSearchQuery struct { - Key OrgProjectMappingViewSearchKey - Method domain.SearchMethod - Value interface{} -} - -type OrgProjectMappingViewSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*OrgProjectMapping - Sequence uint64 - Timestamp time.Time -} - -func (r *OrgProjectMappingViewSearchRequest) GetSearchQuery(key OrgProjectMappingViewSearchKey) (int, *OrgProjectMappingViewSearchQuery) { - for i, q := range r.Queries { - if q.Key == key { - return i, q - } - } - return -1, nil -} diff --git a/internal/project/model/project.go b/internal/project/model/project.go index acbef86a5c..ebedf3cff2 100644 --- a/internal/project/model/project.go +++ b/internal/project/model/project.go @@ -27,68 +27,3 @@ const ( ProjectStateInactive ProjectStateRemoved ) - -func (p *Project) IsActive() bool { - return p.State == ProjectStateActive -} - -func (p *Project) IsValid() bool { - return p.Name != "" -} - -func (p *Project) ContainsRole(role *ProjectRole) bool { - for _, r := range p.Roles { - if r.Key == role.Key { - return true - } - } - return false -} - -func (p *Project) GetApp(appID string) (int, *Application) { - for i, a := range p.Applications { - if a.AppID == appID { - return i, a - } - } - return -1, nil -} - -func (p *Project) GetGrant(grantID string) (int, *ProjectGrant) { - for i, g := range p.Grants { - if g.GrantID == grantID { - return i, g - } - } - return -1, nil -} - -func (p *Project) ContainsGrantForOrg(orgID string) bool { - for _, g := range p.Grants { - if g.GrantedOrgID == orgID { - return true - } - } - return false -} - -func (p *Project) ContainsRoles(roleKeys []string) bool { - for _, r := range roleKeys { - if !p.ContainsRole(&ProjectRole{Key: r}) { - return false - } - } - return true -} - -func (p *Project) ContainsGrantMember(member *ProjectGrantMember) bool { - for _, g := range p.Grants { - if g.GrantID != member.GrantID { - continue - } - if _, m := g.GetMember(member.UserID); m != nil { - return true - } - } - return false -} diff --git a/internal/project/model/project_grant.go b/internal/project/model/project_grant.go index b90ae4059a..5ffdae989a 100644 --- a/internal/project/model/project_grant.go +++ b/internal/project/model/project_grant.go @@ -14,54 +14,9 @@ type ProjectGrant struct { Members []*ProjectGrantMember } -type ProjectGrantIDs struct { - ProjectID string - GrantID string -} - type ProjectGrantState int32 const ( ProjectGrantStateActive ProjectGrantState = iota ProjectGrantStateInactive ) - -func NewProjectGrant(projectID, grantID string) *ProjectGrant { - return &ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, GrantID: grantID, State: ProjectGrantStateActive} -} - -func (p *ProjectGrant) IsActive() bool { - return p.State == ProjectGrantStateActive -} - -func (p *ProjectGrant) IsValid() bool { - return p.GrantedOrgID != "" -} - -func (p *ProjectGrant) GetMember(userID string) (int, *ProjectGrantMember) { - for i, m := range p.Members { - if m.UserID == userID { - return i, m - } - } - return -1, nil -} - -func (p *ProjectGrant) GetRemovedRoles(roleKeys []string) []string { - removed := make([]string, 0) - for _, role := range p.RoleKeys { - if !containsKey(roleKeys, role) { - removed = append(removed, role) - } - } - return removed -} - -func containsKey(roles []string, key string) bool { - for _, role := range roles { - if role == key { - return true - } - } - return false -} diff --git a/internal/project/model/project_grant_member.go b/internal/project/model/project_grant_member.go index ec56441c54..c0aee1af64 100644 --- a/internal/project/model/project_grant_member.go +++ b/internal/project/model/project_grant_member.go @@ -8,11 +8,3 @@ type ProjectGrantMember struct { UserID string Roles []string } - -func NewProjectGrantMember(projectID, grantID, userID string) *ProjectGrantMember { - return &ProjectGrantMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, GrantID: grantID, UserID: userID} -} - -func (p *ProjectGrantMember) IsValid() bool { - return p.AggregateID != "" && p.UserID != "" && len(p.Roles) != 0 -} diff --git a/internal/project/model/project_grant_member_view.go b/internal/project/model/project_grant_member_view.go deleted file mode 100644 index 1b30e4cf7a..0000000000 --- a/internal/project/model/project_grant_member_view.go +++ /dev/null @@ -1,72 +0,0 @@ -package model - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" -) - -type ProjectGrantMemberView struct { - UserID string - GrantID string - ProjectID string - UserName string - Email string - FirstName string - LastName string - DisplayName string - PreferredLoginName string - AvatarURL string - UserResourceOwner string - Roles []string - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type ProjectGrantMemberSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn ProjectGrantMemberSearchKey - Asc bool - Queries []*ProjectGrantMemberSearchQuery -} - -type ProjectGrantMemberSearchKey int32 - -const ( - ProjectGrantMemberSearchKeyUnspecified ProjectGrantMemberSearchKey = iota - ProjectGrantMemberSearchKeyUserName - ProjectGrantMemberSearchKeyEmail - ProjectGrantMemberSearchKeyFirstName - ProjectGrantMemberSearchKeyLastName - ProjectGrantMemberSearchKeyGrantID - ProjectGrantMemberSearchKeyUserID - ProjectGrantMemberSearchKeyProjectID -) - -type ProjectGrantMemberSearchQuery struct { - Key ProjectGrantMemberSearchKey - Method domain.SearchMethod - Value interface{} -} - -type ProjectGrantMemberSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*ProjectGrantMemberView - Sequence uint64 - Timestamp time.Time -} - -func (r *ProjectGrantMemberSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-ZT8df", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} diff --git a/internal/project/model/project_grant_view.go b/internal/project/model/project_grant_view.go deleted file mode 100644 index 02eb78393e..0000000000 --- a/internal/project/model/project_grant_view.go +++ /dev/null @@ -1,90 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" - - "time" -) - -type ProjectGrantView struct { - ProjectID string - Name string - CreationDate time.Time - ChangeDate time.Time - State ProjectState - ResourceOwner string - ResourceOwnerName string - OrgID string - OrgName string - OrgDomain string - Sequence uint64 - GrantID string - GrantedRoleKeys []string -} - -type ProjectGrantViewSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn ProjectGrantViewSearchKey - Asc bool - Queries []*ProjectGrantViewSearchQuery -} - -type ProjectGrantViewSearchKey int32 - -const ( - GrantedProjectSearchKeyUnspecified ProjectGrantViewSearchKey = iota - GrantedProjectSearchKeyName - GrantedProjectSearchKeyProjectID - GrantedProjectSearchKeyGrantID - GrantedProjectSearchKeyOrgID - GrantedProjectSearchKeyResourceOwner - GrantedProjectSearchKeyRoleKeys -) - -type ProjectGrantViewSearchQuery struct { - Key ProjectGrantViewSearchKey - Method domain.SearchMethod - Value interface{} -} - -type ProjectGrantViewSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*ProjectGrantView - Sequence uint64 - Timestamp time.Time -} - -func (r *ProjectGrantViewSearchRequest) GetSearchQuery(key ProjectGrantViewSearchKey) (int, *ProjectGrantViewSearchQuery) { - for i, q := range r.Queries { - if q.Key == key { - return i, q - } - } - return -1, nil -} - -func (r *ProjectGrantViewSearchRequest) AppendMyOrgQuery(orgID string) { - r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyOrgID, Method: domain.SearchMethodEquals, Value: orgID}) -} - -func (r *ProjectGrantViewSearchRequest) AppendNotMyOrgQuery(orgID string) { - r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyOrgID, Method: domain.SearchMethodNotEquals, Value: orgID}) -} - -func (r *ProjectGrantViewSearchRequest) AppendMyResourceOwnerQuery(orgID string) { - r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyResourceOwner, Method: domain.SearchMethodEquals, Value: orgID}) -} - -func (r *ProjectGrantViewSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-0fj3s", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} diff --git a/internal/project/model/project_member.go b/internal/project/model/project_member.go index a07d939c50..a5bce2386e 100644 --- a/internal/project/model/project_member.go +++ b/internal/project/model/project_member.go @@ -8,11 +8,3 @@ type ProjectMember struct { UserID string Roles []string } - -func NewProjectMember(projectID, userID string) *ProjectMember { - return &ProjectMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, UserID: userID} -} - -func (p *ProjectMember) IsValid() bool { - return p.AggregateID != "" && p.UserID != "" && len(p.Roles) != 0 -} diff --git a/internal/project/model/project_member_view.go b/internal/project/model/project_member_view.go deleted file mode 100644 index 3eeecfe191..0000000000 --- a/internal/project/model/project_member_view.go +++ /dev/null @@ -1,73 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" - - "time" -) - -type ProjectMemberView struct { - UserID string - ProjectID string - UserName string - Email string - FirstName string - LastName string - DisplayName string - PreferredLoginName string - AvatarURL string - UserResourceOwner string - Roles []string - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type ProjectMemberSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn ProjectMemberSearchKey - Asc bool - Queries []*ProjectMemberSearchQuery -} - -type ProjectMemberSearchKey int32 - -const ( - ProjectMemberSearchKeyUnspecified ProjectMemberSearchKey = iota - ProjectMemberSearchKeyUserName - ProjectMemberSearchKeyEmail - ProjectMemberSearchKeyFirstName - ProjectMemberSearchKeyLastName - ProjectMemberSearchKeyProjectID - ProjectMemberSearchKeyUserID -) - -type ProjectMemberSearchQuery struct { - Key ProjectMemberSearchKey - Method domain.SearchMethod - Value interface{} -} - -type ProjectMemberSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*ProjectMemberView - Sequence uint64 - Timestamp time.Time -} - -func (r *ProjectMemberSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-389Nd", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} -func (r *ProjectMemberSearchRequest) AppendProjectQuery(projectID string) { - r.Queries = append(r.Queries, &ProjectMemberSearchQuery{Key: ProjectMemberSearchKeyProjectID, Method: domain.SearchMethodEquals, Value: projectID}) -} diff --git a/internal/project/model/project_role.go b/internal/project/model/project_role.go index 43d9f68ffb..9725570523 100644 --- a/internal/project/model/project_role.go +++ b/internal/project/model/project_role.go @@ -9,7 +9,3 @@ type ProjectRole struct { DisplayName string Group string } - -func (p *ProjectRole) IsValid() bool { - return p.AggregateID != "" && p.Key != "" -} diff --git a/internal/project/model/project_role_view.go b/internal/project/model/project_role_view.go deleted file mode 100644 index bf3d8aae1a..0000000000 --- a/internal/project/model/project_role_view.go +++ /dev/null @@ -1,75 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" - - "time" -) - -type ProjectRoleView struct { - ResourceOwner string - OrgID string - ProjectID string - Key string - DisplayName string - Group string - CreationDate time.Time - ChangeDate time.Time - Sequence uint64 -} - -type ProjectRoleSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn ProjectRoleSearchKey - Asc bool - Queries []*ProjectRoleSearchQuery -} - -type ProjectRoleSearchKey int32 - -const ( - ProjectRoleSearchKeyUnspecified ProjectRoleSearchKey = iota - ProjectRoleSearchKeyKey - ProjectRoleSearchKeyProjectID - ProjectRoleSearchKeyOrgID - ProjectRoleSearchKeyResourceOwner - ProjectRoleSearchKeyDisplayName -) - -type ProjectRoleSearchQuery struct { - Key ProjectRoleSearchKey - Method domain.SearchMethod - Value interface{} -} - -type ProjectRoleSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*ProjectRoleView - Sequence uint64 - Timestamp time.Time -} - -func (r *ProjectRoleSearchRequest) AppendMyOrgQuery(orgID string) { - r.Queries = append(r.Queries, &ProjectRoleSearchQuery{Key: ProjectRoleSearchKeyOrgID, Method: domain.SearchMethodEquals, Value: orgID}) -} -func (r *ProjectRoleSearchRequest) AppendProjectQuery(projectID string) { - r.Queries = append(r.Queries, &ProjectRoleSearchQuery{Key: ProjectRoleSearchKeyProjectID, Method: domain.SearchMethodEquals, Value: projectID}) -} - -func (r *ProjectRoleSearchRequest) AppendRoleKeysQuery(keys []string) { - r.Queries = append(r.Queries, &ProjectRoleSearchQuery{Key: ProjectRoleSearchKeyKey, Method: domain.SearchMethodIsOneOf, Value: keys}) -} - -func (r *ProjectRoleSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-92hNf", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} diff --git a/internal/project/model/project_view.go b/internal/project/model/project_view.go deleted file mode 100644 index 95ee5887a4..0000000000 --- a/internal/project/model/project_view.go +++ /dev/null @@ -1,77 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/zerrors" - - "time" -) - -type ProjectView struct { - ProjectID string - Name string - CreationDate time.Time - ChangeDate time.Time - State ProjectState - ResourceOwner string - ProjectRoleAssertion bool - ProjectRoleCheck bool - HasProjectCheck bool - PrivateLabelingSetting domain.PrivateLabelingSetting - Sequence uint64 -} - -type ProjectViewSearchRequest struct { - Offset uint64 - Limit uint64 - SortingColumn ProjectViewSearchKey - Asc bool - Queries []*ProjectViewSearchQuery -} - -type ProjectViewSearchKey int32 - -const ( - ProjectViewSearchKeyUnspecified ProjectViewSearchKey = iota - ProjectViewSearchKeyName - ProjectViewSearchKeyProjectID - ProjectViewSearchKeyResourceOwner -) - -type ProjectViewSearchQuery struct { - Key ProjectViewSearchKey - Method domain.SearchMethod - Value interface{} -} - -type ProjectViewSearchResponse struct { - Offset uint64 - Limit uint64 - TotalResult uint64 - Result []*ProjectView - Sequence uint64 - Timestamp time.Time -} - -func (r *ProjectViewSearchRequest) GetSearchQuery(key ProjectViewSearchKey) (int, *ProjectViewSearchQuery) { - for i, q := range r.Queries { - if q.Key == key { - return i, q - } - } - return -1, nil -} - -func (r *ProjectViewSearchRequest) AppendMyResourceOwnerQuery(orgID string) { - r.Queries = append(r.Queries, &ProjectViewSearchQuery{Key: ProjectViewSearchKeyResourceOwner, Method: domain.SearchMethodEquals, Value: orgID}) -} - -func (r *ProjectViewSearchRequest) EnsureLimit(limit uint64) error { - if r.Limit > limit { - return zerrors.ThrowInvalidArgument(nil, "SEARCH-2M0ds", "Errors.Limit.ExceedsDefault") - } - if r.Limit == 0 { - r.Limit = limit - } - return nil -} diff --git a/internal/project/model/saml_config.go b/internal/project/model/saml_config.go index 2d0ca84697..0b5a9e4bf5 100644 --- a/internal/project/model/saml_config.go +++ b/internal/project/model/saml_config.go @@ -10,7 +10,3 @@ type SAMLConfig struct { Metadata []byte MetadataURL string } - -func (c *SAMLConfig) IsValid() bool { - return !(c.Metadata == nil && c.MetadataURL == "") -} diff --git a/internal/project/repository/view/model/application.go b/internal/project/repository/view/model/application.go deleted file mode 100644 index 006415bb13..0000000000 --- a/internal/project/repository/view/model/application.go +++ /dev/null @@ -1,231 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - http_util "github.com/zitadel/zitadel/internal/api/http" - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ApplicationKeyID = "id" - ApplicationKeyProjectID = "project_id" - ApplicationKeyResourceOwner = "resource_owner" - ApplicationKeyOIDCClientID = "oidc_client_id" - ApplicationKeyName = "app_name" -) - -type ApplicationView struct { - ID string `json:"appId" gorm:"column:id;primary_key"` - ProjectID string `json:"-" gorm:"column:project_id"` - Name string `json:"name" gorm:"column:app_name"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - State int32 `json:"-" gorm:"column:app_state"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - ProjectRoleAssertion bool `json:"projectRoleAssertion" gorm:"column:project_role_assertion"` - ProjectRoleCheck bool `json:"projectRoleCheck" gorm:"column:project_role_check"` - HasProjectCheck bool `json:"hasProjectCheck" gorm:"column:has_project_check"` - PrivateLabelingSetting domain.PrivateLabelingSetting `json:"privateLabelingSetting" gorm:"column:private_labeling_setting"` - - IsOIDC bool `json:"-" gorm:"column:is_oidc"` - OIDCVersion int32 `json:"oidcVersion" gorm:"column:oidc_version"` - OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"` - OIDCRedirectUris database.TextArray[string] `json:"redirectUris" gorm:"column:oidc_redirect_uris"` - OIDCResponseTypes database.Array[domain.OIDCResponseType] `json:"responseTypes" gorm:"column:oidc_response_types"` - OIDCGrantTypes database.Array[domain.OIDCGrantType] `json:"grantTypes" gorm:"column:oidc_grant_types"` - OIDCApplicationType int32 `json:"applicationType" gorm:"column:oidc_application_type"` - OIDCAuthMethodType int32 `json:"authMethodType" gorm:"column:oidc_auth_method_type"` - OIDCPostLogoutRedirectUris database.TextArray[string] `json:"postLogoutRedirectUris" gorm:"column:oidc_post_logout_redirect_uris"` - NoneCompliant bool `json:"-" gorm:"column:none_compliant"` - ComplianceProblems database.TextArray[string] `json:"-" gorm:"column:compliance_problems"` - DevMode bool `json:"devMode" gorm:"column:dev_mode"` - OriginAllowList database.TextArray[string] `json:"-" gorm:"column:origin_allow_list"` - AdditionalOrigins database.TextArray[string] `json:"additionalOrigins" gorm:"column:additional_origins"` - 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"` - IDTokenUserinfoAssertion bool `json:"idTokenUserinfoAssertion" gorm:"column:id_token_userinfo_assertion"` - ClockSkew time.Duration `json:"clockSkew" gorm:"column:clock_skew"` - - IsSAML bool `json:"-" gorm:"column:is_saml"` - Metadata []byte `json:"metadata" gorm:"column:metadata"` - MetadataURL string `json:"metadata_url" gorm:"column:metadata_url"` - - Sequence uint64 `json:"-" gorm:"sequence"` -} - -func OIDCResponseTypesToModel(oidctypes []domain.OIDCResponseType) []model.OIDCResponseType { - result := make([]model.OIDCResponseType, len(oidctypes)) - for i, t := range oidctypes { - result[i] = model.OIDCResponseType(t) - } - return result -} - -func OIDCGrantTypesToModel(granttypes []domain.OIDCGrantType) []model.OIDCGrantType { - result := make([]model.OIDCGrantType, len(granttypes)) - for i, t := range granttypes { - result[i] = model.OIDCGrantType(t) - } - return result -} - -func (a *ApplicationView) AppendEventIfMyApp(event *models.Event) (err error) { - view := new(ApplicationView) - switch event.Type() { - case project.ApplicationAddedType: - err = view.SetData(event) - if err != nil { - return err - } - case project.ApplicationChangedType, - project.OIDCConfigAddedType, - project.OIDCConfigChangedType, - project.APIConfigAddedType, - project.APIConfigChangedType, - project.ApplicationDeactivatedType, - project.ApplicationReactivatedType, - project.SAMLConfigAddedType, - project.SAMLConfigChangedType: - err = view.SetData(event) - if err != nil { - return err - } - case project.ApplicationRemovedType: - err = view.SetData(event) - if err != nil { - return err - } - case project.ProjectChangedType: - return a.AppendEvent(event) - case project.ProjectRemovedType: - return a.AppendEvent(event) - default: - return nil - } - if view.ID == a.ID { - return a.AppendEvent(event) - } - return nil -} - -func (a *ApplicationView) AppendEvent(event *models.Event) (err error) { - a.Sequence = event.Seq - a.ChangeDate = event.CreationDate - switch event.Type() { - case project.ApplicationAddedType: - a.setRootData(event) - a.CreationDate = event.CreationDate - a.ResourceOwner = event.ResourceOwner - err = a.SetData(event) - case project.OIDCConfigAddedType: - a.IsOIDC = true - err = a.SetData(event) - if err != nil { - return err - } - a.setCompliance() - return a.setOriginAllowList() - case project.SAMLConfigAddedType: - a.IsSAML = true - return a.SetData(event) - case project.APIConfigAddedType: - a.IsOIDC = false - return a.SetData(event) - case project.ApplicationChangedType: - return a.SetData(event) - case project.OIDCConfigChangedType: - err = a.SetData(event) - if err != nil { - return err - } - a.setCompliance() - return a.setOriginAllowList() - case project.SAMLConfigChangedType: - return a.SetData(event) - case project.APIConfigChangedType: - return a.SetData(event) - case project.ProjectChangedType: - return a.setProjectChanges(event) - case project.ApplicationDeactivatedType: - a.State = int32(model.AppStateInactive) - case project.ApplicationReactivatedType: - a.State = int32(model.AppStateActive) - case project.ApplicationRemovedType, project.ProjectRemovedType: - a.State = int32(model.AppStateRemoved) - } - return err -} - -func (a *ApplicationView) setRootData(event *models.Event) { - a.ProjectID = event.AggregateID -} - -func (a *ApplicationView) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, a); err != nil { - logging.Log("EVEN-lo9ds").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-8suie", "Could not unmarshal data") - } - return nil -} - -func (a *ApplicationView) setOriginAllowList() error { - allowList := make(database.TextArray[string], 0) - for _, redirect := range a.OIDCRedirectUris { - origin, err := http_util.GetOriginFromURLString(redirect) - if err != nil { - return err - } - if !http_util.IsOriginAllowed(allowList, origin) { - allowList = append(allowList, origin) - } - } - for _, origin := range a.AdditionalOrigins { - if !http_util.IsOriginAllowed(allowList, origin) { - allowList = append(allowList, origin) - } - } - a.OriginAllowList = allowList - return nil -} - -func (a *ApplicationView) setCompliance() { - compliance := model.GetOIDCCompliance(model.OIDCVersion(a.OIDCVersion), model.OIDCApplicationType(a.OIDCApplicationType), OIDCGrantTypesToModel(a.OIDCGrantTypes), OIDCResponseTypesToModel(a.OIDCResponseTypes), model.OIDCAuthMethodType(a.OIDCAuthMethodType), a.OIDCRedirectUris) - a.NoneCompliant = compliance.NoneCompliant - a.ComplianceProblems = compliance.Problems -} - -func (a *ApplicationView) setProjectChanges(event *models.Event) error { - changes := struct { - ProjectRoleAssertion *bool `json:"projectRoleAssertion,omitempty"` - ProjectRoleCheck *bool `json:"projectRoleCheck,omitempty"` - HasProjectCheck *bool `json:"hasProjectCheck,omitempty"` - PrivateLabelingSetting *domain.PrivateLabelingSetting `json:"privateLabelingSetting,omitempty"` - }{} - if err := json.Unmarshal(event.Data, &changes); err != nil { - logging.Log("EVEN-DFbfg").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-Bw221", "Could not unmarshal data") - } - if changes.ProjectRoleAssertion != nil { - a.ProjectRoleAssertion = *changes.ProjectRoleAssertion - } - if changes.ProjectRoleCheck != nil { - a.ProjectRoleCheck = *changes.ProjectRoleCheck - } - if changes.HasProjectCheck != nil { - a.HasProjectCheck = *changes.HasProjectCheck - } - if changes.PrivateLabelingSetting != nil { - a.PrivateLabelingSetting = *changes.PrivateLabelingSetting - } - return nil -} diff --git a/internal/project/repository/view/model/application_test.go b/internal/project/repository/view/model/application_test.go deleted file mode 100644 index f37e6386b2..0000000000 --- a/internal/project/repository/view/model/application_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package model - -import ( - "encoding/json" - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/project" -) - -func mockAppData(app *es_model.Application) []byte { - data, _ := json.Marshal(app) - return data -} - -func mockOIDCConfigData(config *es_model.OIDCConfig) []byte { - data, _ := json.Marshal(config) - return data -} - -func TestApplicationAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - app *ApplicationView - } - tests := []struct { - name string - args args - result *ApplicationView - }{ - { - name: "append added app event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ApplicationAddedType, Data: mockAppData(&es_model.Application{Name: "AppName"})}, - app: &ApplicationView{}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateActive)}, - }, - { - name: "append changed app event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ApplicationChangedType, Data: mockAppData(&es_model.Application{Name: "AppNameChanged"})}, - app: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateActive)}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppNameChanged", State: int32(model.AppStateActive)}, - }, - { - name: "append deactivate app event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ApplicationDeactivatedType}, - app: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateActive)}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateInactive)}, - }, - { - name: "append reactivate app event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ApplicationReactivatedType}, - app: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateInactive)}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateActive)}, - }, - { - name: "append added oidc config event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.OIDCConfigAddedType, Data: mockOIDCConfigData(&es_model.OIDCConfig{ClientID: "clientID"})}, - app: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", State: int32(model.AppStateActive)}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", IsOIDC: true, OIDCClientID: "clientID", State: int32(model.AppStateActive)}, - }, - { - name: "append changed oidc config event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.OIDCConfigAddedType, Data: mockOIDCConfigData(&es_model.OIDCConfig{ClientID: "clientIDChanged"})}, - app: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", OIDCClientID: "clientID", State: int32(model.AppStateActive)}, - }, - result: &ApplicationView{ProjectID: "AggregateID", Name: "AppName", IsOIDC: true, OIDCClientID: "clientIDChanged", State: int32(model.AppStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.app.AppendEvent(tt.args.event) - if tt.args.app.ProjectID != tt.result.ProjectID { - t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.app.ProjectID) - } - if tt.args.app.Name != tt.result.Name { - t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, tt.args.app.Name) - } - if tt.args.app.State != tt.result.State { - t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, tt.args.app.State) - } - if tt.args.app.IsOIDC != tt.result.IsOIDC { - t.Errorf("got wrong result IsOIDC: expected: %v, actual: %v ", tt.result.IsOIDC, tt.args.app.IsOIDC) - } - if tt.args.app.OIDCClientID != tt.result.OIDCClientID { - t.Errorf("got wrong result OIDCClientID: expected: %v, actual: %v ", tt.result.OIDCClientID, tt.args.app.OIDCClientID) - } - }) - } -} diff --git a/internal/project/repository/view/model/org_project_mapping.go b/internal/project/repository/view/model/org_project_mapping.go deleted file mode 100644 index 929725cce5..0000000000 --- a/internal/project/repository/view/model/org_project_mapping.go +++ /dev/null @@ -1,16 +0,0 @@ -package model - -const ( - OrgProjectMappingKeyProjectID = "project_id" - OrgProjectMappingKeyOrgID = "org_id" - OrgProjectMappingKeyProjectGrantID = "project_grant_id" - OrgProjectMappingKeyInstanceID = "instance_id" - OrgProjectMappingOwnerRemoved = "owner_removed" -) - -type OrgProjectMapping struct { - ProjectID string `json:"-" gorm:"column:project_id;primary_key"` - OrgID string `json:"-" gorm:"column:org_id;primary_key"` - ProjectGrantID string `json:"-" gorm:"column:project_grant_id"` - InstanceID string `json:"instanceID" gorm:"column:instance_id"` -} diff --git a/internal/project/repository/view/model/org_project_mapping_query.go b/internal/project/repository/view/model/org_project_mapping_query.go deleted file mode 100644 index 9587579336..0000000000 --- a/internal/project/repository/view/model/org_project_mapping_query.go +++ /dev/null @@ -1,67 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - proj_model "github.com/zitadel/zitadel/internal/project/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type OrgProjectMappingSearchRequest proj_model.OrgProjectMappingViewSearchRequest -type OrgProjectMappingSearchQuery proj_model.OrgProjectMappingViewSearchQuery -type OrgProjectMappingSearchKey proj_model.OrgProjectMappingViewSearchKey - -func (req OrgProjectMappingSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req OrgProjectMappingSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req OrgProjectMappingSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == proj_model.OrgProjectMappingSearchKeyUnspecified { - return nil - } - return OrgProjectMappingSearchKey(req.SortingColumn) -} - -func (req OrgProjectMappingSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req OrgProjectMappingSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = OrgProjectMappingSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req OrgProjectMappingSearchQuery) GetKey() repository.ColumnKey { - return OrgProjectMappingSearchKey(req.Key) -} - -func (req OrgProjectMappingSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req OrgProjectMappingSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key OrgProjectMappingSearchKey) ToColumnName() string { - switch proj_model.OrgProjectMappingViewSearchKey(key) { - case proj_model.OrgProjectMappingSearchKeyOrgID: - return OrgProjectMappingKeyOrgID - case proj_model.OrgProjectMappingSearchKeyProjectID: - return OrgProjectMappingKeyProjectID - case proj_model.OrgProjectMappingSearchKeyProjectGrantID: - return OrgProjectMappingKeyProjectGrantID - case proj_model.OrgProjectMappingSearchKeyInstanceID: - return OrgProjectMappingKeyInstanceID - case proj_model.OrgProjectMappingSearchKeyOwnerRemoved: - return OrgProjectMappingOwnerRemoved - default: - return "" - } -} diff --git a/internal/project/repository/view/model/project.go b/internal/project/repository/view/model/project.go deleted file mode 100644 index a13eb205c8..0000000000 --- a/internal/project/repository/view/model/project.go +++ /dev/null @@ -1,81 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ProjectKeyProjectID = "project_id" - ProjectKeyResourceOwner = "resource_owner" - ProjectKeyName = "project_name" -) - -type ProjectView struct { - ProjectID string `json:"-" gorm:"column:project_id;primary_key"` - Name string `json:"name" gorm:"column:project_name"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - State int32 `json:"-" gorm:"column:project_state"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - ProjectRoleAssertion bool `json:"projectRoleAssertion" gorm:"column:project_role_assertion"` - ProjectRoleCheck bool `json:"projectRoleCheck" gorm:"column:project_role_check"` - HasProjectCheck bool `json:"hasProjectCheck" gorm:"column:has_project_check"` - PrivateLabelingSetting domain.PrivateLabelingSetting `json:"privateLabelingSetting" gorm:"column:private_labeling_setting"` - Sequence uint64 `json:"-" gorm:"column:sequence"` -} - -func (p *ProjectView) AppendEvent(event *models.Event) (err error) { - p.ChangeDate = event.CreationDate - p.Sequence = event.Seq - switch event.Type() { - case project.ProjectAddedType: - p.State = int32(model.ProjectStateActive) - p.CreationDate = event.CreationDate - p.setRootData(event) - err = p.setData(event) - case project.ProjectChangedType: - err = p.setData(event) - case project.ProjectDeactivatedType: - p.State = int32(model.ProjectStateInactive) - case project.ProjectReactivatedType: - p.State = int32(model.ProjectStateActive) - case project.ProjectRemovedType: - p.State = int32(model.ProjectStateRemoved) - } - return err -} - -func (p *ProjectView) setRootData(event *models.Event) { - p.ProjectID = event.AggregateID - p.ResourceOwner = event.ResourceOwner -} - -func (p *ProjectView) setData(event *models.Event) error { - if err := json.Unmarshal(event.Data, p); err != nil { - logging.Log("EVEN-dlo92").WithError(err).Error("could not unmarshal event data") - return err - } - return nil -} - -func (p *ProjectView) setProjectData(event *models.Event) error { - project := new(ProjectView) - return project.SetData(event) -} - -func (p *ProjectView) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, p); err != nil { - logging.Log("EVEN-sk9Sj").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-s9ols", "Could not unmarshal data") - } - return nil -} diff --git a/internal/project/repository/view/model/project_grant.go b/internal/project/repository/view/model/project_grant.go deleted file mode 100644 index 2b6557dcca..0000000000 --- a/internal/project/repository/view/model/project_grant.go +++ /dev/null @@ -1,99 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ProjectGrantKeyProjectID = "project_id" - ProjectGrantKeyGrantID = "grant_id" - ProjectGrantKeyOrgID = "org_id" - ProjectGrantKeyResourceOwner = "resource_owner" - ProjectGrantKeyName = "project_name" - ProjectGrantKeyRoleKeys = "granted_role_keys" -) - -type ProjectGrantView struct { - GrantID string `json:"-" gorm:"column:grant_id;primary_key"` - ProjectID string `json:"-" gorm:"column:project_id"` - OrgID string `json:"-" gorm:"column:org_id"` - Name string `json:"name" gorm:"column:project_name"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - State int32 `json:"-" gorm:"column:project_state"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - ResourceOwnerName string `json:"-" gorm:"column:resource_owner_name"` - OrgName string `json:"-" gorm:"column:org_name"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - GrantedRoleKeys database.TextArray[string] `json:"-" gorm:"column:granted_role_keys"` -} - -type ProjectGrant struct { - GrantID string `json:"grantId"` - GrantedOrgID string `json:"grantedOrgId"` - RoleKeys []string `json:"roleKeys"` - InstanceID string `json:"instanceID"` -} - -func (p *ProjectGrantView) AppendEvent(event *models.Event) (err error) { - p.ChangeDate = event.CreationDate - p.Sequence = event.Seq - switch event.Type() { - case project.GrantAddedType: - p.State = int32(model.ProjectStateActive) - p.CreationDate = event.CreationDate - p.setRootData(event) - err = p.setProjectGrantData(event) - case project.GrantChangedType, project.GrantCascadeChangedType: - err = p.setProjectGrantData(event) - case project.GrantDeactivatedType: - p.State = int32(model.ProjectStateInactive) - case project.GrantReactivatedType: - p.State = int32(model.ProjectStateActive) - } - return err -} - -func (p *ProjectGrantView) setRootData(event *models.Event) { - p.ProjectID = event.AggregateID - p.ResourceOwner = event.ResourceOwner -} - -func (p *ProjectGrantView) setData(event *models.Event) error { - if err := json.Unmarshal(event.Data, p); err != nil { - logging.Log("EVEN-dlo92").WithError(err).Error("could not unmarshal event data") - return err - } - return nil -} - -func (p *ProjectGrantView) setProjectGrantData(event *models.Event) error { - grant := new(ProjectGrant) - err := grant.SetData(event) - if err != nil { - return err - } - if grant.GrantedOrgID != "" { - p.OrgID = grant.GrantedOrgID - } - p.GrantID = grant.GrantID - p.GrantedRoleKeys = grant.RoleKeys - return nil -} - -func (p *ProjectGrant) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, p); err != nil { - logging.Log("EVEN-dlo92").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-s9ols", "Could not unmarshal data") - } - return nil -} diff --git a/internal/project/repository/view/model/project_grant_member.go b/internal/project/repository/view/model/project_grant_member.go deleted file mode 100644 index 119692cfd9..0000000000 --- a/internal/project/repository/view/model/project_grant_member.go +++ /dev/null @@ -1,68 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ProjectGrantMemberKeyUserID = "user_id" - ProjectGrantMemberKeyGrantID = "grant_id" - ProjectGrantMemberKeyProjectID = "project_id" - ProjectGrantMemberKeyUserName = "user_name" - ProjectGrantMemberKeyEmail = "email" - ProjectGrantMemberKeyFirstName = "first_name" - ProjectGrantMemberKeyLastName = "last_name" -) - -type ProjectGrantMemberView struct { - UserID string `json:"userId" gorm:"column:user_id;primary_key"` - GrantID string `json:"grantId" gorm:"column:grant_id;primary_key"` - ProjectID string `json:"-" gorm:"column:project_id"` - UserName string `json:"-" gorm:"column:user_name"` - Email string `json:"-" gorm:"column:email_address"` - FirstName string `json:"-" gorm:"column:first_name"` - LastName string `json:"-" gorm:"column:last_name"` - DisplayName string `json:"-" gorm:"column:display_name"` - Roles database.TextArray[string] `json:"roles" gorm:"column:roles"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"` - AvatarKey string `json:"-" gorm:"column:avatar_key"` - UserResourceOwner string `json:"-" gorm:"column:user_resource_owner"` - - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` -} - -func (r *ProjectGrantMemberView) AppendEvent(event *models.Event) (err error) { - r.Sequence = event.Seq - r.ChangeDate = event.CreationDate - switch event.Type() { - case project.GrantMemberAddedType: - r.setRootData(event) - r.CreationDate = event.CreationDate - err = r.SetData(event) - case project.GrantMemberChangedType: - err = r.SetData(event) - } - return err -} - -func (r *ProjectGrantMemberView) setRootData(event *models.Event) { - r.ProjectID = event.AggregateID -} - -func (r *ProjectGrantMemberView) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, r); err != nil { - logging.Log("EVEN-slo9s").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-0plew", "Could not unmarshal data") - } - return nil -} diff --git a/internal/project/repository/view/model/project_grant_member_test.go b/internal/project/repository/view/model/project_grant_member_test.go deleted file mode 100644 index 57028979ab..0000000000 --- a/internal/project/repository/view/model/project_grant_member_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package model - -import ( - "encoding/json" - "reflect" - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/project" -) - -func mockProjectGrantMemberData(member *es_model.ProjectGrantMember) []byte { - data, _ := json.Marshal(member) - return data -} - -func TestGrantedProjectMemberAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - member *ProjectGrantMemberView - } - tests := []struct { - name string - args args - result *ProjectGrantMemberView - }{ - { - name: "append added member event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantMemberAddedType, ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", UserID: "UserID", Roles: []string{"Role"}})}, - member: &ProjectGrantMemberView{}, - }, - result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"Role"}}, - }, - { - name: "append changed member event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantMemberAddedType, ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", Roles: []string{"RoleChanged"}})}, - member: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"Role"}}, - }, - result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"RoleChanged"}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.member.AppendEvent(tt.args.event) - if tt.args.member.ProjectID != tt.result.ProjectID { - t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.member.ProjectID) - } - if tt.args.member.UserID != tt.result.UserID { - t.Errorf("got wrong result userID: expected: %v, actual: %v ", tt.result.UserID, tt.args.member.UserID) - } - if tt.args.member.GrantID != tt.result.GrantID { - t.Errorf("got wrong result ProjectGrantID: expected: %v, actual: %v ", tt.result.GrantID, tt.args.member.GrantID) - } - if !reflect.DeepEqual(tt.args.member.Roles, tt.result.Roles) { - t.Errorf("got wrong result Roles: expected: %v, actual: %v ", tt.result.Roles, tt.args.member.Roles) - } - }) - } -} diff --git a/internal/project/repository/view/model/project_grant_test.go b/internal/project/repository/view/model/project_grant_test.go deleted file mode 100644 index 3f777182b0..0000000000 --- a/internal/project/repository/view/model/project_grant_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package model - -import ( - "encoding/json" - "reflect" - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/project" -) - -func mockProjectData(project *es_model.Project) []byte { - data, _ := json.Marshal(project) - return data -} - -func mockProjectGrantData(grant *es_model.ProjectGrant) []byte { - data, _ := json.Marshal(grant) - return data -} - -func TestProjectGrantAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - project *ProjectGrantView - } - tests := []struct { - name string - args args - result *ProjectGrantView - }{ - { - name: "append added project grant event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantAddedType, ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", GrantedOrgID: "GrantedOrgID", RoleKeys: []string{"Role"}})}, - project: &ProjectGrantView{}, - }, - result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}}, - }, - { - name: "append change project grant event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantChangedType, ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", RoleKeys: []string{"RoleChanged"}})}, - project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}}, - }, - result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"RoleChanged"}}, - }, - { - name: "append deactivate project grant event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantDeactivatedType, ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID"})}, - project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}}, - }, - result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: []string{"Role"}}, - }, - { - name: "append reactivate project grant event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.GrantReactivatedType, ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID"})}, - project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: []string{"Role"}}, - }, - result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.project.AppendEvent(tt.args.event) - if tt.args.project.ProjectID != tt.result.ProjectID { - t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.project.ProjectID) - } - if tt.args.project.OrgID != tt.result.OrgID { - t.Errorf("got wrong result orgID: expected: %v, actual: %v ", tt.result.OrgID, tt.args.project.OrgID) - } - if tt.args.project.ResourceOwner != tt.result.ResourceOwner { - t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.project.ResourceOwner) - } - if tt.args.project.Name != tt.result.Name { - t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, tt.args.project.Name) - } - if tt.args.project.State != tt.result.State { - t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, tt.args.project.State) - } - if !reflect.DeepEqual(tt.args.project.GrantedRoleKeys, tt.result.GrantedRoleKeys) { - t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.GrantedRoleKeys, tt.args.project.GrantedRoleKeys) - } - }) - } -} diff --git a/internal/project/repository/view/model/project_member.go b/internal/project/repository/view/model/project_member.go deleted file mode 100644 index d81f584c68..0000000000 --- a/internal/project/repository/view/model/project_member.go +++ /dev/null @@ -1,66 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ProjectMemberKeyUserID = "user_id" - ProjectMemberKeyProjectID = "project_id" - ProjectMemberKeyUserName = "user_name" - ProjectMemberKeyEmail = "email" - ProjectMemberKeyFirstName = "first_name" - ProjectMemberKeyLastName = "last_name" -) - -type ProjectMemberView struct { - UserID string `json:"userId" gorm:"column:user_id;primary_key"` - ProjectID string `json:"-" gorm:"column:project_id;primary_key"` - UserName string `json:"-" gorm:"column:user_name"` - Email string `json:"-" gorm:"column:email_address"` - FirstName string `json:"-" gorm:"column:first_name"` - LastName string `json:"-" gorm:"column:last_name"` - DisplayName string `json:"-" gorm:"column:display_name"` - Roles database.TextArray[string] `json:"roles" gorm:"column:roles"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"` - AvatarKey string `json:"-" gorm:"column:avatar_key"` - UserResourceOwner string `json:"-" gorm:"column:user_resource_owner"` - - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` -} - -func (r *ProjectMemberView) AppendEvent(event *models.Event) (err error) { - r.Sequence = event.Seq - r.ChangeDate = event.CreationDate - switch event.Type() { - case project.MemberAddedType: - r.setRootData(event) - r.CreationDate = event.CreationDate - err = r.SetData(event) - case project.MemberChangedType: - err = r.SetData(event) - } - return err -} - -func (r *ProjectMemberView) setRootData(event *models.Event) { - r.ProjectID = event.AggregateID -} - -func (r *ProjectMemberView) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, r); err != nil { - logging.Log("EVEN-slo9s").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data") - } - return nil -} diff --git a/internal/project/repository/view/model/project_member_test.go b/internal/project/repository/view/model/project_member_test.go deleted file mode 100644 index dff8425665..0000000000 --- a/internal/project/repository/view/model/project_member_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package model - -import ( - "encoding/json" - "reflect" - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/project" -) - -func mockProjectMemberData(member *es_model.ProjectMember) []byte { - data, _ := json.Marshal(member) - return data -} - -func TestProjectMemberAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - member *ProjectMemberView - } - tests := []struct { - name string - args args - result *ProjectMemberView - }{ - { - name: "append added member event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.MemberAddedType, ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: []string{"Role"}})}, - member: &ProjectMemberView{}, - }, - result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"Role"}}, - }, - { - name: "append changed member event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.MemberAddedType, ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: []string{"RoleChanged"}})}, - member: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"Role"}}, - }, - result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"RoleChanged"}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.member.AppendEvent(tt.args.event) - if tt.args.member.ProjectID != tt.result.ProjectID { - t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.member.ProjectID) - } - if tt.args.member.UserID != tt.result.UserID { - t.Errorf("got wrong result userID: expected: %v, actual: %v ", tt.result.UserID, tt.args.member.UserID) - } - if !reflect.DeepEqual(tt.args.member.Roles, tt.result.Roles) { - t.Errorf("got wrong result Roles: expected: %v, actual: %v ", tt.result.Roles, tt.args.member.Roles) - } - }) - } -} diff --git a/internal/project/repository/view/model/project_test.go b/internal/project/repository/view/model/project_test.go deleted file mode 100644 index 4731d98f23..0000000000 --- a/internal/project/repository/view/model/project_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package model - -import ( - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/project/model" - es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/project" -) - -func TestProjectAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - project *ProjectView - } - tests := []struct { - name string - args args - result *ProjectView - }{ - { - name: "append added project event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ProjectAddedType, ResourceOwner: "GrantedOrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectName"})}, - project: &ProjectView{}, - }, - result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateActive)}, - }, - { - name: "append change project event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ProjectChangedType, ResourceOwner: "GrantedOrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectNameChanged"})}, - project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateActive)}, - }, - result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectNameChanged", State: int32(model.ProjectStateActive)}, - }, - { - name: "append project deactivate event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ProjectDeactivatedType, ResourceOwner: "GrantedOrgID"}, - project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateActive)}, - }, - result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateInactive)}, - }, - { - name: "append project reactivate event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: project.ProjectReactivatedType, ResourceOwner: "GrantedOrgID"}, - project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateInactive)}, - }, - result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", Name: "ProjectName", State: int32(model.ProjectStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.project.AppendEvent(tt.args.event) - if tt.args.project.ProjectID != tt.result.ProjectID { - t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.project.ProjectID) - } - if tt.args.project.ResourceOwner != tt.result.ResourceOwner { - t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.project.ResourceOwner) - } - if tt.args.project.Name != tt.result.Name { - t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, tt.args.project.Name) - } - if tt.args.project.State != tt.result.State { - t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, tt.args.project.State) - } - }) - } -} diff --git a/internal/project/repository/view/org_project_mapping_view.go b/internal/project/repository/view/org_project_mapping_view.go deleted file mode 100644 index 76d98c815a..0000000000 --- a/internal/project/repository/view/org_project_mapping_view.go +++ /dev/null @@ -1,70 +0,0 @@ -package view - -import ( - "github.com/jinzhu/gorm" - - "github.com/zitadel/zitadel/internal/domain" - proj_model "github.com/zitadel/zitadel/internal/project/model" - "github.com/zitadel/zitadel/internal/project/repository/view/model" - "github.com/zitadel/zitadel/internal/view/repository" - "github.com/zitadel/zitadel/internal/zerrors" -) - -func OrgProjectMappingByIDs(db *gorm.DB, table, orgID, projectID, instanceID string) (*model.OrgProjectMapping, error) { - orgProjectMapping := new(model.OrgProjectMapping) - - projectIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyProjectID, Value: projectID, Method: domain.SearchMethodEquals} - orgIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOrgID, Value: orgID, Method: domain.SearchMethodEquals} - instanceIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - ownerRemovedQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, projectIDQuery, orgIDQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, orgProjectMapping) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-fn9fs", "Errors.OrgProjectMapping.NotExisting") - } - return orgProjectMapping, err -} - -func PutOrgProjectMapping(db *gorm.DB, table string, grant *model.OrgProjectMapping) error { - save := repository.PrepareSave(table) - return save(db, grant) -} - -func DeleteOrgProjectMapping(db *gorm.DB, table, orgID, projectID, instanceID string) error { - projectIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), Value: projectID} - orgIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOrgID), Value: orgID} - instanceIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), Value: instanceID} - delete := repository.PrepareDeleteByKeys(table, projectIDSearch, orgIDSearch, instanceIDSearch) - return delete(db) -} - -func DeleteInstanceOrgProjectMappings(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID) - return delete(db) -} - -func UpdateOwnerRemovedOrgProjectMappings(db *gorm.DB, table, instanceID, orgID string) error { - update := repository.PrepareUpdateByKeys(table, - model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOwnerRemoved), - true, - repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), Value: instanceID}, - repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOrgID), Value: orgID}, - ) - return update(db) -} - -func DeleteOrgProjectMappingsByProjectID(db *gorm.DB, table, projectID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), projectID}, - repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID}, - ) - return delete(db) -} - -func DeleteOrgProjectMappingsByProjectGrantID(db *gorm.DB, table, projectGrantID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectGrantID), projectGrantID}, - repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID}, - ) - return delete(db) -} diff --git a/internal/query/projection/user_grant.go b/internal/query/projection/user_grant.go index c3ae22c487..963cad395d 100644 --- a/internal/query/projection/user_grant.go +++ b/internal/query/projection/user_grant.go @@ -285,7 +285,7 @@ func (p *userGrantProjection) reduceDeactivated(event eventstore.Event) (*handle } func (p *userGrantProjection) reduceReactivated(event eventstore.Event) (*handler.Statement, error) { - if _, ok := event.(*usergrant.UserGrantDeactivatedEvent); !ok { + if _, ok := event.(*usergrant.UserGrantReactivatedEvent); !ok { return nil, zerrors.ThrowInvalidArgumentf(nil, "PROJE-DGsKh", "reduce.wrong.event.type %s", usergrant.UserGrantReactivatedType) } diff --git a/internal/query/projection/user_grant_test.go b/internal/query/projection/user_grant_test.go index 128a97fe5c..22644d6e8c 100644 --- a/internal/query/projection/user_grant_test.go +++ b/internal/query/projection/user_grant_test.go @@ -345,7 +345,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { usergrant.UserGrantReactivatedType, usergrant.AggregateType, nil, - ), usergrant.UserGrantDeactivatedEventMapper), + ), usergrant.UserGrantReactivatedEventMapper), }, reduce: (&userGrantProjection{}).reduceReactivated, want: wantReduce{ diff --git a/internal/query/search_query.go b/internal/query/search_query.go index c92f155d2a..b4944a8f2d 100644 --- a/internal/query/search_query.go +++ b/internal/query/search_query.go @@ -8,6 +8,7 @@ import ( sq "github.com/Masterminds/squirrel" + "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/domain" ) @@ -255,7 +256,7 @@ func NewInTextQuery(col Column, values []string) (*InTextQuery, error) { }, nil } -type TextQuery struct { +type textQuery struct { Column Column Text string Compare TextComparison @@ -269,21 +270,38 @@ var ( ErrEmptyValues = errors.New("values array must not be empty") ) -func NewTextQuery(col Column, value string, compare TextComparison) (*TextQuery, error) { +func NewTextQuery(col Column, value string, compare TextComparison) (*textQuery, error) { if compare < 0 || compare >= textCompareMax { return nil, ErrInvalidCompare } if col.isZero() { return nil, ErrMissingColumn } - return &TextQuery{ + // handle the comparisons which use (i)like and therefore need to escape potential wildcards in the value + switch compare { + case TextEqualsIgnoreCase, + TextStartsWith, + TextStartsWithIgnoreCase, + TextEndsWith, + TextEndsWithIgnoreCase, + TextContains, + TextContainsIgnoreCase: + value = database.EscapeLikeWildcards(value) + case TextEquals, + TextListContains, + TextNotEquals, + textCompareMax: + // do nothing + } + + return &textQuery{ Column: col, Text: value, Compare: compare, }, nil } -func (q *TextQuery) Col() Column { +func (q *textQuery) Col() Column { return q.Column } @@ -296,11 +314,11 @@ func (q *InTextQuery) comp() sq.Sqlizer { return sq.Eq{q.Column.identifier(): q.Values} } -func (q *TextQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { +func (q *textQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { return query.Where(q.comp()) } -func (q *TextQuery) comp() sq.Sqlizer { +func (q *textQuery) comp() sq.Sqlizer { switch q.Compare { case TextEquals: return sq.Eq{q.Column.identifier(): q.Text} @@ -346,32 +364,6 @@ const ( textCompareMax ) -// Deprecated: Use TextComparison, will be removed as soon as all calls are changed to query -func TextComparisonFromMethod(m domain.SearchMethod) TextComparison { - switch m { - case domain.SearchMethodEquals: - return TextEquals - case domain.SearchMethodEqualsIgnoreCase: - return TextEqualsIgnoreCase - case domain.SearchMethodStartsWith: - return TextStartsWith - case domain.SearchMethodStartsWithIgnoreCase: - return TextStartsWithIgnoreCase - case domain.SearchMethodContains: - return TextContains - case domain.SearchMethodContainsIgnoreCase: - return TextContainsIgnoreCase - case domain.SearchMethodEndsWith: - return TextEndsWith - case domain.SearchMethodEndsWithIgnoreCase: - return TextEndsWithIgnoreCase - case domain.SearchMethodListContains: - return TextListContains - default: - return textCompareMax - } -} - type NumberQuery struct { Column Column Number interface{} diff --git a/internal/query/search_query_test.go b/internal/query/search_query_test.go index ac56eb6eee..c64b2c131c 100644 --- a/internal/query/search_query_test.go +++ b/internal/query/search_query_test.go @@ -191,7 +191,7 @@ func TestNewSubSelect(t *testing.T) { name: "no column 1", args: args{ column: Column{}, - queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}, + queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}, }, wantErr: func(err error) bool { return errors.Is(err, ErrMissingColumn) @@ -201,7 +201,7 @@ func TestNewSubSelect(t *testing.T) { name: "no column name 1", args: args{ column: testNoCol, - queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}, + queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}, }, wantErr: func(err error) bool { return errors.Is(err, ErrMissingColumn) @@ -211,22 +211,22 @@ func TestNewSubSelect(t *testing.T) { name: "correct 1", args: args{ column: testCol, - queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}, + queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}, }, want: &SubSelect{ Column: testCol, - Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}, + Queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}, }, }, { name: "correct 3", args: args{ column: testCol, - queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}}, + queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}, &textQuery{testCol, "horst2", TextEquals}, &textQuery{testCol, "horst3", TextEquals}}, }, want: &SubSelect{ Column: testCol, - Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}}, + Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}, &textQuery{testCol, "horst2", TextEquals}, &textQuery{testCol, "horst3", TextEquals}}, }, }, } @@ -275,7 +275,7 @@ func TestSubSelect_comp(t *testing.T) { name: "queries 1", fields: fields{ Column: testCol, - Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}, + Queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}, }, want: want{ query: sq.Select("test_table.test_col").From("test_table").Where(sq.Eq{"test_table.test_col": interface{}("horst")}), @@ -285,7 +285,7 @@ func TestSubSelect_comp(t *testing.T) { name: "queries 1 with alias", fields: fields{ Column: testColAlias, - Queries: []SearchQuery{&TextQuery{testColAlias, "horst", TextEquals}}, + Queries: []SearchQuery{&textQuery{testColAlias, "horst", TextEquals}}, }, want: want{ query: sq.Select("test_alias.test_col").From("test_table AS test_alias").Where(sq.Eq{"test_alias.test_col": interface{}("horst")}), @@ -295,7 +295,7 @@ func TestSubSelect_comp(t *testing.T) { name: "queries 3", fields: fields{ Column: testCol, - Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}, &TextQuery{testCol, "horst2", TextEquals}, &TextQuery{testCol, "horst3", TextEquals}}, + Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}, &textQuery{testCol, "horst2", TextEquals}, &textQuery{testCol, "horst3", TextEquals}}, }, want: want{ query: sq.Select("test_table.test_col").From("test_table").From("test_table").Where(sq.Eq{"test_table.test_col": "horst1"}).From("test_table").Where(sq.Eq{"test_table.test_col": "horst2"}).From("test_table").Where(sq.Eq{"test_table.test_col": "horst3"}), @@ -585,12 +585,12 @@ func TestNewListQuery(t *testing.T) { name: "correct", args: args{ column: testCol, - data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}}}, + data: &SubSelect{Column: testCol, Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}}}, compare: ListIn, }, want: &ListQuery{ Column: testCol, - Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst1", TextEquals}}}, + Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}}}, Compare: ListIn, }, }, @@ -697,7 +697,7 @@ func TestListQuery_comp(t *testing.T) { name: "in subquery text", fields: fields{ Column: testCol, - Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&TextQuery{testCol, "horst", TextEquals}}}, + Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&textQuery{testCol, "horst", TextEquals}}}, Compare: ListIn, }, want: want{ @@ -779,7 +779,7 @@ func TestNewTextQuery(t *testing.T) { tests := []struct { name string args args - want *TextQuery + want *textQuery wantErr func(error) bool }{ { @@ -827,18 +827,317 @@ func TestNewTextQuery(t *testing.T) { }, }, { - name: "correct", + name: "equals", args: args{ column: testCol, value: "hurst", compare: TextEquals, }, - want: &TextQuery{ + want: &textQuery{ Column: testCol, Text: "hurst", Compare: TextEquals, }, }, + { + name: "equals ignore case", + args: args{ + column: testCol, + value: "hurst", + compare: TextEqualsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextEqualsIgnoreCase, + }, + }, + { + name: "equals ignore case % wildcard", + args: args{ + column: testCol, + value: "hu%rst", + compare: TextEqualsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hu\\%rst", + Compare: TextEqualsIgnoreCase, + }, + }, + { + name: "equals ignore case _ wildcard", + args: args{ + column: testCol, + value: "hu_rst", + compare: TextEqualsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hu\\_rst", + Compare: TextEqualsIgnoreCase, + }, + }, + { + name: "equals ignore case _, % wildcards", + args: args{ + column: testCol, + value: "h_urst%", + compare: TextEqualsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "h\\_urst\\%", + Compare: TextEqualsIgnoreCase, + }, + }, + { + name: "not equal", + args: args{ + column: testCol, + value: "hurst", + compare: TextNotEquals, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextNotEquals, + }, + }, + { + name: "starts with", + args: args{ + column: testCol, + value: "hurst", + compare: TextStartsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextStartsWith, + }, + }, + { + name: "starts with _ wildcard", + args: args{ + column: testCol, + value: "_hurst", + compare: TextStartsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "\\_hurst", + Compare: TextStartsWith, + }, + }, + { + name: "starts with % wildcard", + args: args{ + column: testCol, + value: "hurst%", + compare: TextStartsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst\\%", + Compare: TextStartsWith, + }, + }, + { + name: "starts with %, % wildcard", + args: args{ + column: testCol, + value: "hu%%rst", + compare: TextStartsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hu\\%\\%rst", + Compare: TextStartsWith, + }, + }, + { + name: "starts with ignore case", + args: args{ + column: testCol, + value: "hurst", + compare: TextStartsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextStartsWithIgnoreCase, + }, + }, + { + name: "starts with ignore case _ wildcard", + args: args{ + column: testCol, + value: "hur_st", + compare: TextStartsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hur\\_st", + Compare: TextStartsWithIgnoreCase, + }, + }, + { + name: "starts with ignore case % wildcard", + args: args{ + column: testCol, + value: "hurst%", + compare: TextStartsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst\\%", + Compare: TextStartsWithIgnoreCase, + }, + }, + { + name: "starts with ignore case _, _ wildcard", + args: args{ + column: testCol, + value: "h_r_t", + compare: TextStartsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "h\\_r\\_t", + Compare: TextStartsWithIgnoreCase, + }, + }, + { + name: "ends with", + args: args{ + column: testCol, + value: "hurst", + compare: TextEndsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextEndsWith, + }, + }, + { + name: "ends with % wildcard", + args: args{ + column: testCol, + value: "%hurst", + compare: TextEndsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "\\%hurst", + Compare: TextEndsWith, + }, + }, + { + name: "ends with _ wildcard", + args: args{ + column: testCol, + value: "hurst_", + compare: TextEndsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst\\_", + Compare: TextEndsWith, + }, + }, + { + name: "ends with _, % wildcard", + args: args{ + column: testCol, + value: "hurst_%", + compare: TextEndsWith, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst\\_\\%", + Compare: TextEndsWith, + }, + }, + { + name: "ends with ignore case", + args: args{ + column: testCol, + value: "hurst", + compare: TextEndsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextEndsWithIgnoreCase, + }, + }, + { + name: "ends with ignore case _, %, _ wildcards", + args: args{ + column: testCol, + value: "h_r_t%", + compare: TextEndsWithIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "h\\_r\\_t\\%", + Compare: TextEndsWithIgnoreCase, + }, + }, + { + name: "contains", + args: args{ + column: testCol, + value: "hurst", + compare: TextContains, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextContains, + }, + }, + { + name: "contains % wildcard", + args: args{ + column: testCol, + value: "%", + compare: TextContains, + }, + want: &textQuery{ + Column: testCol, + Text: "\\%", + Compare: TextContains, + }, + }, + { + name: "contains ignore csae", + args: args{ + column: testCol, + value: "hurst", + compare: TextContainsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurst", + Compare: TextContainsIgnoreCase, + }, + }, + { + name: "contains ignore csae _ wildcard", + args: args{ + column: testCol, + value: "hurs_", + compare: TextContainsIgnoreCase, + }, + want: &textQuery{ + Column: testCol, + Text: "hurs\\_", + Compare: TextContainsIgnoreCase, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -894,6 +1193,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.ILike{"test_table.test_col": "Hurst"}, }, }, + { + name: "equals ignore case wildcard", + fields: fields{ + Column: testCol, + Text: "Hu%%rst", + Compare: TextEqualsIgnoreCase, + }, + want: want{ + query: sq.ILike{"test_table.test_col": "Hu\\%\\%rst"}, + }, + }, { name: "starts with", fields: fields{ @@ -905,6 +1215,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.Like{"test_table.test_col": "Hurst%"}, }, }, + { + name: "starts with wildcards", + fields: fields{ + Column: testCol, + Text: "_Hurst%", + Compare: TextStartsWith, + }, + want: want{ + query: sq.Like{"test_table.test_col": "\\_Hurst\\%%"}, + }, + }, { name: "starts with ignore case", fields: fields{ @@ -916,6 +1237,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.ILike{"test_table.test_col": "Hurst%"}, }, }, + { + name: "starts with ignore case wildcards", + fields: fields{ + Column: testCol, + Text: "Hurst%", + Compare: TextStartsWithIgnoreCase, + }, + want: want{ + query: sq.ILike{"test_table.test_col": "Hurst\\%%"}, + }, + }, { name: "ends with", fields: fields{ @@ -927,6 +1259,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.Like{"test_table.test_col": "%Hurst"}, }, }, + { + name: "ends with wildcards", + fields: fields{ + Column: testCol, + Text: "Hurst%", + Compare: TextEndsWith, + }, + want: want{ + query: sq.Like{"test_table.test_col": "%Hurst\\%"}, + }, + }, { name: "ends with ignore case", fields: fields{ @@ -938,6 +1281,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.ILike{"test_table.test_col": "%Hurst"}, }, }, + { + name: "ends with ignore case wildcards", + fields: fields{ + Column: testCol, + Text: "%Hurst", + Compare: TextEndsWithIgnoreCase, + }, + want: want{ + query: sq.ILike{"test_table.test_col": "%\\%Hurst"}, + }, + }, { name: "contains", fields: fields{ @@ -949,6 +1303,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.Like{"test_table.test_col": "%Hurst%"}, }, }, + { + name: "contains wildcards", + fields: fields{ + Column: testCol, + Text: "Hu%rst%", + Compare: TextContains, + }, + want: want{ + query: sq.Like{"test_table.test_col": "%Hu\\%rst\\%%"}, + }, + }, { name: "containts ignore case", fields: fields{ @@ -960,6 +1325,17 @@ func TestTextQuery_comp(t *testing.T) { query: sq.ILike{"test_table.test_col": "%Hurst%"}, }, }, + { + name: "contains ignore case wildcards", + fields: fields{ + Column: testCol, + Text: "%Hurst%", + Compare: TextContainsIgnoreCase, + }, + want: want{ + query: sq.ILike{"test_table.test_col": "%\\%Hurst\\%%"}, + }, + }, { name: "list containts", fields: fields{ @@ -999,10 +1375,10 @@ func TestTextQuery_comp(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := &TextQuery{ - Column: tt.fields.Column, - Text: tt.fields.Text, - Compare: tt.fields.Compare, + s, _ := NewTextQuery(tt.fields.Column, tt.fields.Text, tt.fields.Compare) + if s == nil { + // used to check correct behavior of comp + s = &textQuery{Column: tt.fields.Column, Text: tt.fields.Text, Compare: tt.fields.Compare} } query := s.comp() if query == nil && tt.want.isNil { @@ -1018,95 +1394,6 @@ func TestTextQuery_comp(t *testing.T) { } } -func TestTextComparisonFromMethod(t *testing.T) { - type args struct { - m domain.SearchMethod - } - tests := []struct { - name string - args args - want TextComparison - }{ - { - name: "equals", - args: args{ - m: domain.SearchMethodEquals, - }, - want: TextEquals, - }, - { - name: "equals ignore case", - args: args{ - m: domain.SearchMethodEqualsIgnoreCase, - }, - want: TextEqualsIgnoreCase, - }, - { - name: "starts with", - args: args{ - m: domain.SearchMethodStartsWith, - }, - want: TextStartsWith, - }, - { - name: "starts with ignore case", - args: args{ - m: domain.SearchMethodStartsWithIgnoreCase, - }, - want: TextStartsWithIgnoreCase, - }, - { - name: "ends with", - args: args{ - m: domain.SearchMethodEndsWith, - }, - want: TextEndsWith, - }, - { - name: "ends with ignore case", - args: args{ - m: domain.SearchMethodEndsWithIgnoreCase, - }, - want: TextEndsWithIgnoreCase, - }, - { - name: "contains", - args: args{ - m: domain.SearchMethodContains, - }, - want: TextContains, - }, - { - name: "list contains", - args: args{ - m: domain.SearchMethodListContains, - }, - want: TextListContains, - }, - { - name: "containts ignore case", - args: args{ - m: domain.SearchMethodContainsIgnoreCase, - }, - want: TextContainsIgnoreCase, - }, - { - name: "invalid search method", - args: args{ - m: -1, - }, - want: textCompareMax, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := TextComparisonFromMethod(tt.args.m); got != tt.want { - t.Errorf("TextCompareFromMethod() = %v, want %v", got, tt.want) - } - }) - } -} - func TestNewNumberQuery(t *testing.T) { type args struct { column Column diff --git a/internal/query/user_by_id.sql b/internal/query/user_by_id.sql index 67ffbb371a..8f1113de06 100644 --- a/internal/query/user_by_id.sql +++ b/internal/query/user_by_id.sql @@ -23,8 +23,6 @@ WITH login_names AS (SELECT (p.is_default IS TRUE AND p.instance_id = $2) OR (p.instance_id = $2 AND p.resource_owner = u.resource_owner) ) - AND - u.id = $1 ORDER BY is_default LIMIT 1 ) p ON TRUE @@ -33,6 +31,9 @@ WITH login_names AS (SELECT ON u.instance_id = d.instance_id AND u.resource_owner = d.resource_owner + WHERE + u.instance_id = $2 + AND u.id = $1 ) SELECT u.id diff --git a/internal/query/user_by_login_name.sql b/internal/query/user_by_login_name.sql index b9da3daa87..cf25638fa6 100644 --- a/internal/query/user_by_login_name.sql +++ b/internal/query/user_by_login_name.sql @@ -30,6 +30,12 @@ WITH found_users AS ( u.instance_id = d.instance_id AND u.resource_owner = d.resource_owner AND CASE WHEN p.must_be_domain THEN d.name_lower = $2 ELSE TRUE END + WHERE + u.instance_id = $4 + AND u.user_name_lower IN ( + $1, + $3 + ) ), login_names AS (SELECT fu.id user_id diff --git a/internal/query/user_notify_by_id.sql b/internal/query/user_notify_by_id.sql index 16905c02e6..1087a1316b 100644 --- a/internal/query/user_notify_by_id.sql +++ b/internal/query/user_notify_by_id.sql @@ -24,8 +24,6 @@ WITH login_names AS ( (p.is_default IS TRUE AND p.instance_id = $2) OR (p.instance_id = $2 AND p.resource_owner = u.resource_owner) ) - AND - u.id = $1 ORDER BY is_default LIMIT 1 ) p ON TRUE @@ -34,6 +32,9 @@ WITH login_names AS ( ON u.instance_id = d.instance_id AND u.resource_owner = d.resource_owner + WHERE + u.instance_id = $2 + AND u.id = $1 ) SELECT u.id diff --git a/internal/query/user_notify_by_login_name.sql b/internal/query/user_notify_by_login_name.sql index 47bcc8a88a..1347e6cb3c 100644 --- a/internal/query/user_notify_by_login_name.sql +++ b/internal/query/user_notify_by_login_name.sql @@ -30,6 +30,12 @@ WITH found_users AS ( u.instance_id = d.instance_id AND u.resource_owner = d.resource_owner AND CASE WHEN p.must_be_domain THEN d.name_lower = $2 ELSE TRUE END + WHERE + u.instance_id = $4 + AND u.user_name_lower IN ( + $1, + $3 + ) ), login_names AS (SELECT fu.id user_id diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 35b333a26e..6806d78ebd 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -7,7 +7,6 @@ import ( "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore/v1/models" - iam_model "github.com/zitadel/zitadel/internal/iam/model" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -231,20 +230,6 @@ func (u *UserView) IsPasswordlessReady() bool { return false } -func (u *UserView) HasRequiredOrgMFALevel(policy *iam_model.LoginPolicyView) bool { - if !policy.ForceMFA { - return true - } - switch u.MFAMaxSetUp { - case domain.MFALevelSecondFactor: - return policy.HasSecondFactors() - case domain.MFALevelMultiFactor: - return policy.HasMultiFactors() - default: - return false - } -} - func (u *UserView) GetProfile() (*Profile, error) { if u.HumanView == nil { return nil, zerrors.ThrowPreconditionFailed(nil, "MODEL-WLTce", "Errors.User.NotHuman") diff --git a/internal/user/repository/view/external_idp_view.go b/internal/user/repository/view/external_idp_view.go deleted file mode 100644 index 198017dc2a..0000000000 --- a/internal/user/repository/view/external_idp_view.go +++ /dev/null @@ -1,147 +0,0 @@ -package view - -import ( - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/view/repository" - "github.com/zitadel/zitadel/internal/zerrors" - - "github.com/jinzhu/gorm" - - usr_model "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/user/repository/view/model" -) - -func ExternalIDPByExternalUserIDAndIDPConfigID(db *gorm.DB, table, externalUserID, idpConfigID, instanceID string) (*model.ExternalIDPView, error) { - user := new(model.ExternalIDPView) - userIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyExternalUserID, - Method: domain.SearchMethodEquals, - Value: externalUserID, - } - idpConfigIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyIdpConfigID, - Method: domain.SearchMethodEquals, - Value: idpConfigID, - } - instanceIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Mso9f", "Errors.ExternalIDP.NotFound") - } - return user, err -} - -func ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(db *gorm.DB, table, externalUserID, idpConfigID, resourceOwner, instanceID string) (*model.ExternalIDPView, error) { - user := new(model.ExternalIDPView) - userIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyExternalUserID, - Method: domain.SearchMethodEquals, - Value: externalUserID, - } - idpConfigIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyIdpConfigID, - Method: domain.SearchMethodEquals, - Value: idpConfigID, - } - resourceOwnerQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyResourceOwner, - Method: domain.SearchMethodEquals, - Value: resourceOwner, - } - instanceIDQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, resourceOwnerQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Sf8sd", "Errors.ExternalIDP.NotFound") - } - return user, err -} - -func ExternalIDPsByIDPConfigID(db *gorm.DB, table, idpConfigID, instanceID string) ([]*model.ExternalIDPView, error) { - externalIDPs := make([]*model.ExternalIDPView, 0) - orgIDQuery := &usr_model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyIdpConfigID, - Method: domain.SearchMethodEquals, - Value: idpConfigID, - } - instanceIDQuery := &usr_model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &usr_model.ExternalIDPSearchQuery{ - Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareSearchQuery(table, model.ExternalIDPSearchRequest{ - Queries: []*usr_model.ExternalIDPSearchQuery{orgIDQuery, instanceIDQuery, ownerRemovedQuery}, - }) - _, err := query(db, &externalIDPs) - return externalIDPs, err -} - -func PutExternalIDPs(db *gorm.DB, table string, externalIDPs ...*model.ExternalIDPView) error { - save := repository.PrepareBulkSave(table) - u := make([]interface{}, len(externalIDPs)) - for i, idp := range externalIDPs { - u[i] = idp - } - return save(db, u...) -} - -func PutExternalIDP(db *gorm.DB, table string, idp *model.ExternalIDPView) error { - save := repository.PrepareSave(table) - return save(db, idp) -} - -func DeleteExternalIDP(db *gorm.DB, table, externalUserID, idpConfigID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyExternalUserID), Value: externalUserID}, - repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyIdpConfigID), Value: idpConfigID}, - repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), Value: instanceID}, - ) - return delete(db) -} - -func DeleteExternalIDPsByUserID(db *gorm.DB, table, userID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyUserID), userID}, - repository.Key{model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), instanceID}, - ) - return delete(db) -} - -func DeleteInstanceExternalIDPs(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), instanceID) - return delete(db) -} - -func UpdateOrgOwnerRemovedExternalIDPs(db *gorm.DB, table, instanceID, aggID string) error { - update := repository.PrepareUpdateByKeys(table, - model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyOwnerRemoved), - true, - repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), Value: instanceID}, - repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyResourceOwner), Value: aggID}, - ) - return update(db) -} diff --git a/internal/user/repository/view/model/external_idp_query.go b/internal/user/repository/view/model/external_idp_query.go deleted file mode 100644 index d6f193cb7d..0000000000 --- a/internal/user/repository/view/model/external_idp_query.go +++ /dev/null @@ -1,69 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - usr_model "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type ExternalIDPSearchRequest usr_model.ExternalIDPSearchRequest -type ExternalIDPSearchQuery usr_model.ExternalIDPSearchQuery -type ExternalIDPSearchKey usr_model.ExternalIDPSearchKey - -func (req ExternalIDPSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req ExternalIDPSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req ExternalIDPSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == usr_model.ExternalIDPSearchKeyUnspecified { - return nil - } - return ExternalIDPSearchKey(req.SortingColumn) -} - -func (req ExternalIDPSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req ExternalIDPSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = ExternalIDPSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req ExternalIDPSearchQuery) GetKey() repository.ColumnKey { - return ExternalIDPSearchKey(req.Key) -} - -func (req ExternalIDPSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req ExternalIDPSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key ExternalIDPSearchKey) ToColumnName() string { - switch usr_model.ExternalIDPSearchKey(key) { - case usr_model.ExternalIDPSearchKeyExternalUserID: - return ExternalIDPKeyExternalUserID - case usr_model.ExternalIDPSearchKeyUserID: - return ExternalIDPKeyUserID - case usr_model.ExternalIDPSearchKeyIdpConfigID: - return ExternalIDPKeyIDPConfigID - case usr_model.ExternalIDPSearchKeyResourceOwner: - return ExternalIDPKeyResourceOwner - case usr_model.ExternalIDPSearchKeyInstanceID: - return ExternalIDPKeyInstanceID - case usr_model.ExternalIDPSearchKeyOwnerRemoved: - return ExternalIDPKeyOwnerRemoved - default: - return "" - } -} diff --git a/internal/user/repository/view/model/external_idps.go b/internal/user/repository/view/model/external_idps.go deleted file mode 100644 index d27e0a0b26..0000000000 --- a/internal/user/repository/view/model/external_idps.go +++ /dev/null @@ -1,59 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - user_repo "github.com/zitadel/zitadel/internal/repository/user" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - ExternalIDPKeyExternalUserID = "external_user_id" - ExternalIDPKeyUserID = "user_id" - ExternalIDPKeyIDPConfigID = "idp_config_id" - ExternalIDPKeyResourceOwner = "resource_owner" - ExternalIDPKeyInstanceID = "instance_id" - ExternalIDPKeyOwnerRemoved = "owner_removed" -) - -type ExternalIDPView struct { - ExternalUserID string `json:"userID" gorm:"column:external_user_id;primary_key"` - IDPConfigID string `json:"idpConfigID" gorm:"column:idp_config_id;primary_key"` - UserID string `json:"-" gorm:"column:user_id"` - IDPName string `json:"-" gorm:"column:idp_name"` - UserDisplayName string `json:"displayName" gorm:"column:user_display_name"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"` -} - -func (i *ExternalIDPView) AppendEvent(event *models.Event) (err error) { - i.Sequence = event.Seq - i.ChangeDate = event.CreationDate - if event.Typ == user_repo.UserIDPLinkAddedType { - i.setRootData(event) - i.CreationDate = event.CreationDate - err = i.SetData(event) - } - return err -} - -func (r *ExternalIDPView) setRootData(event *models.Event) { - r.UserID = event.AggregateID - r.ResourceOwner = event.ResourceOwner - r.InstanceID = event.InstanceID -} - -func (r *ExternalIDPView) SetData(event *models.Event) error { - if err := json.Unmarshal(event.Data, r); err != nil { - logging.Log("EVEN-48sfs").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data") - } - return nil -} diff --git a/internal/user/repository/view/model/notify_user.go b/internal/user/repository/view/model/notify_user.go deleted file mode 100644 index 7ab7fc664d..0000000000 --- a/internal/user/repository/view/model/notify_user.go +++ /dev/null @@ -1,132 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - org_model "github.com/zitadel/zitadel/internal/org/model" - "github.com/zitadel/zitadel/internal/repository/user" - es_model "github.com/zitadel/zitadel/internal/user/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - NotifyUserKeyUserID = "id" - NotifyUserKeyResourceOwner = "resource_owner" - NotifyUserKeyInstanceID = "instance_id" -) - -type NotifyUser struct { - ID string `json:"-" gorm:"column:id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - UserName string `json:"userName" gorm:"column:user_name"` - LoginNames database.TextArray[string] `json:"-" gorm:"column:login_names"` - PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"` - FirstName string `json:"firstName" gorm:"column:first_name"` - LastName string `json:"lastName" gorm:"column:last_name"` - NickName string `json:"nickName" gorm:"column:nick_name"` - DisplayName string `json:"displayName" gorm:"column:display_name"` - PreferredLanguage string `json:"preferredLanguage" gorm:"column:preferred_language"` - Gender int32 `json:"gender" gorm:"column:gender"` - LastEmail string `json:"email" gorm:"column:last_email"` - VerifiedEmail string `json:"-" gorm:"column:verified_email"` - LastPhone string `json:"phone" gorm:"column:last_phone"` - VerifiedPhone string `json:"-" gorm:"column:verified_phone"` - PasswordSet bool `json:"-" gorm:"column:password_set"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - State int32 `json:"-" gorm:"-"` - InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"` -} - -func (u *NotifyUser) GenerateLoginName(domain string, appendDomain bool) string { - if !appendDomain { - return u.UserName - } - return u.UserName + "@" + domain -} - -func (u *NotifyUser) SetLoginNames(userLoginMustBeDomain bool, domains []*org_model.OrgDomain) { - loginNames := make([]string, 0) - for _, d := range domains { - if d.Verified { - loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true)) - } - } - if !userLoginMustBeDomain { - loginNames = append(loginNames, u.UserName) - } - u.LoginNames = loginNames -} - -func (u *NotifyUser) AppendEvent(event *models.Event) (err error) { - u.ChangeDate = event.CreationDate - u.Sequence = event.Seq - switch event.Type() { - case user.UserV1AddedType, - user.UserV1RegisteredType, - user.HumanRegisteredType, - user.HumanAddedType, - user.MachineAddedEventType: - u.CreationDate = event.CreationDate - u.setRootData(event) - err = u.setData(event) - if err != nil { - return err - } - err = u.setPasswordData(event) - case user.UserV1ProfileChangedType, - user.UserV1EmailChangedType, - user.UserV1PhoneChangedType, - user.HumanProfileChangedType, - user.HumanEmailChangedType, - user.HumanPhoneChangedType, - user.UserUserNameChangedType: - err = u.setData(event) - case user.UserV1EmailVerifiedType, - user.HumanEmailVerifiedType: - u.VerifiedEmail = u.LastEmail - case user.UserV1PhoneRemovedType, - user.HumanPhoneRemovedType: - u.VerifiedPhone = "" - u.LastPhone = "" - case user.UserV1PhoneVerifiedType, - user.HumanPhoneVerifiedType: - u.VerifiedPhone = u.LastPhone - case user.UserV1PasswordChangedType, - user.HumanPasswordChangedType: - err = u.setPasswordData(event) - case user.UserRemovedType: - u.State = int32(UserStateDeleted) - } - return err -} - -func (u *NotifyUser) setRootData(event *models.Event) { - u.ID = event.AggregateID - u.ResourceOwner = event.ResourceOwner - u.InstanceID = event.InstanceID -} - -func (u *NotifyUser) setData(event *models.Event) error { - if err := json.Unmarshal(event.Data, u); err != nil { - logging.Log("MODEL-lso9e").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-8iows", "could not unmarshal data") - } - return nil -} - -func (u *NotifyUser) setPasswordData(event *models.Event) error { - password := new(es_model.Password) - if err := json.Unmarshal(event.Data, password); err != nil { - logging.Log("MODEL-dfhw6").WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-BHFD2", "could not unmarshal data") - } - u.PasswordSet = password.Secret != nil || password.EncodedHash != "" - return nil -} diff --git a/internal/user/repository/view/model/notify_user_query.go b/internal/user/repository/view/model/notify_user_query.go deleted file mode 100644 index e91299f386..0000000000 --- a/internal/user/repository/view/model/notify_user_query.go +++ /dev/null @@ -1,63 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - usr_model "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type NotifyUserSearchRequest usr_model.NotifyUserSearchRequest -type NotifyUserSearchQuery usr_model.NotifyUserSearchQuery -type NotifyUserSearchKey usr_model.NotifyUserSearchKey - -func (req NotifyUserSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req NotifyUserSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req NotifyUserSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == usr_model.NotifyUserSearchKeyUnspecified { - return nil - } - return NotifyUserSearchKey(req.SortingColumn) -} - -func (req NotifyUserSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req NotifyUserSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = NotifyUserSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req NotifyUserSearchQuery) GetKey() repository.ColumnKey { - return NotifyUserSearchKey(req.Key) -} - -func (req NotifyUserSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req NotifyUserSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key NotifyUserSearchKey) ToColumnName() string { - switch usr_model.NotifyUserSearchKey(key) { - case usr_model.NotifyUserSearchKeyUserID: - return NotifyUserKeyUserID - case usr_model.NotifyUserSearchKeyResourceOwner: - return NotifyUserKeyResourceOwner - case usr_model.NotifyUserSearchKeyInstanceID: - return NotifyUserKeyInstanceID - default: - return "" - } -} diff --git a/internal/user/repository/view/model/notify_user_test.go b/internal/user/repository/view/model/notify_user_test.go deleted file mode 100644 index 7644ba03ab..0000000000 --- a/internal/user/repository/view/model/notify_user_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package model - -import ( - "testing" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/user" - es_model "github.com/zitadel/zitadel/internal/user/repository/eventsourcing/model" -) - -func TestNotifyUserAppendEvent(t *testing.T) { - type args struct { - event *es_models.Event - user *NotifyUser - } - tests := []struct { - name string - args args - result *NotifyUser - }{ - { - name: "append added user event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1AddedType, ResourceOwner: "GrantedOrgID", Data: mockUserData(getFullHuman(nil))}, - user: &NotifyUser{}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - { - name: "append added human event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.HumanAddedType, ResourceOwner: "GrantedOrgID", Data: mockUserData(getFullHuman(nil))}, - user: &NotifyUser{}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - { - name: "append change user profile event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1ProfileChangedType, ResourceOwner: "GrantedOrgID", Data: mockProfileData(&es_model.Profile{FirstName: "FirstNameChanged"})}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstNameChanged", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - { - name: "append change user email event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1EmailChangedType, ResourceOwner: "GrantedOrgID", Data: mockEmailData(&es_model.Email{EmailAddress: "EmailChanged"})}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "EmailChanged", LastPhone: "Phone"}, - }, - { - name: "append change user email event, existing email", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1EmailChangedType, ResourceOwner: "GrantedOrgID", Data: mockEmailData(&es_model.Email{EmailAddress: "EmailChanged"})}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", VerifiedEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "EmailChanged", VerifiedEmail: "Email", LastPhone: "Phone"}, - }, - { - name: "append verify user email event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1EmailVerifiedType, ResourceOwner: "GrantedOrgID"}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", VerifiedEmail: "Email", LastPhone: "Phone"}, - }, - { - name: "append change user phone event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1PhoneChangedType, ResourceOwner: "GrantedOrgID", Data: mockPhoneData(&es_model.Phone{PhoneNumber: "PhoneChanged"})}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "PhoneChanged"}, - }, - { - name: "append change user phone event, existing phone", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1PhoneChangedType, ResourceOwner: "GrantedOrgID", Data: mockPhoneData(&es_model.Phone{PhoneNumber: "PhoneChanged"})}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone", VerifiedPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "PhoneChanged", VerifiedPhone: "Phone"}, - }, - { - name: "append verify user phone event", - args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Seq: 1, Typ: user.UserV1PhoneVerifiedType, ResourceOwner: "GrantedOrgID"}, - user: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, - }, - result: &NotifyUser{ID: "AggregateID", ResourceOwner: "GrantedOrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone", VerifiedPhone: "Phone"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.AppendEvent(tt.args.event) - if tt.args.user.ID != tt.result.ID { - t.Errorf("got wrong result ID: expected: %v, actual: %v ", tt.result.ID, tt.args.user.ID) - } - if tt.args.user.FirstName != tt.result.FirstName { - t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, tt.args.user.FirstName) - } - if tt.args.user.LastName != tt.result.LastName { - t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, tt.args.user.FirstName) - } - if tt.args.user.ResourceOwner != tt.result.ResourceOwner { - t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.user.ResourceOwner) - } - if tt.args.user.LastEmail != tt.result.LastEmail { - t.Errorf("got wrong result LastEmail: expected: %v, actual: %v ", tt.result.LastEmail, tt.args.user.LastEmail) - } - if tt.args.user.VerifiedEmail != tt.result.VerifiedEmail { - t.Errorf("got wrong result VerifiedEmail: expected: %v, actual: %v ", tt.result.VerifiedEmail, tt.args.user.VerifiedEmail) - } - if tt.args.user.LastPhone != tt.result.LastPhone { - t.Errorf("got wrong result LastPhone: expected: %v, actual: %v ", tt.result.LastPhone, tt.args.user.LastPhone) - } - if tt.args.user.VerifiedPhone != tt.result.VerifiedPhone { - t.Errorf("got wrong result VerifiedPhone: expected: %v, actual: %v ", tt.result.VerifiedPhone, tt.args.user.VerifiedPhone) - } - }) - } -} diff --git a/internal/user/repository/view/model/user_membership.go b/internal/user/repository/view/model/user_membership.go deleted file mode 100644 index 716ac6f59e..0000000000 --- a/internal/user/repository/view/model/user_membership.go +++ /dev/null @@ -1,135 +0,0 @@ -package model - -import ( - "encoding/json" - "time" - - "github.com/zitadel/logging" - - "github.com/zitadel/zitadel/internal/database" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - iam_es_model "github.com/zitadel/zitadel/internal/iam/repository/eventsourcing/model" - org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model" - proj_es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/zerrors" -) - -const ( - UserMembershipKeyUserID = "user_id" - UserMembershipKeyAggregateID = "aggregate_id" - UserMembershipKeyObjectID = "object_id" - UserMembershipKeyResourceOwner = "resource_owner" - UserMembershipKeyMemberType = "member_type" - UserMembershipKeyInstanceID = "instance_id" -) - -type UserMembershipView struct { - UserID string `json:"-" gorm:"column:user_id;primary_key"` - MemberType int32 `json:"-" gorm:"column:member_type;primary_key"` - AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"` - ObjectID string `json:"-" gorm:"column:object_id;primary_key"` - - Roles database.TextArray[string] `json:"-" gorm:"column:roles"` - DisplayName string `json:"-" gorm:"column:display_name"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - ResourceOwnerName string `json:"-" gorm:"column:resource_owner_name"` - Sequence uint64 `json:"-" gorm:"column:sequence"` - InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"` -} - -func (u *UserMembershipView) AppendEvent(event *models.Event) (err error) { - u.ChangeDate = event.CreationDate - u.Sequence = event.Seq - - switch event.Type() { - case instance.MemberAddedEventType: - u.setRootData(event, model.MemberTypeIam) - err = u.setIamMemberData(event) - case instance.MemberChangedEventType, - instance.MemberRemovedEventType, - instance.MemberCascadeRemovedEventType: - err = u.setIamMemberData(event) - case org.MemberAddedEventType: - u.setRootData(event, model.MemberTypeOrganisation) - err = u.setOrgMemberData(event) - case org.MemberChangedEventType, - org.MemberRemovedEventType, - org.MemberCascadeRemovedEventType: - err = u.setOrgMemberData(event) - case project.MemberAddedType: - u.setRootData(event, model.MemberTypeProject) - err = u.setProjectMemberData(event) - case project.MemberChangedType, - project.MemberRemovedType, - project.MemberCascadeRemovedType: - err = u.setProjectMemberData(event) - case project.GrantMemberAddedType: - u.setRootData(event, model.MemberTypeProjectGrant) - err = u.setProjectGrantMemberData(event) - case project.GrantMemberChangedType, - project.GrantMemberRemovedType, - project.GrantMemberCascadeRemovedType: - err = u.setProjectGrantMemberData(event) - } - return err -} - -func (u *UserMembershipView) setRootData(event *models.Event, memberType model.MemberType) { - u.CreationDate = event.CreationDate - u.AggregateID = event.AggregateID - u.ObjectID = event.AggregateID - u.ResourceOwner = event.ResourceOwner - u.MemberType = int32(memberType) - u.InstanceID = event.InstanceID -} - -func (u *UserMembershipView) setIamMemberData(event *models.Event) error { - member := new(iam_es_model.IAMMember) - if err := json.Unmarshal(event.Data, member); err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data") - } - u.UserID = member.UserID - u.Roles = member.Roles - return nil -} - -func (u *UserMembershipView) setOrgMemberData(event *models.Event) error { - member := new(org_es_model.OrgMember) - if err := json.Unmarshal(event.Data, member); err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data") - } - u.UserID = member.UserID - u.Roles = member.Roles - return nil -} - -func (u *UserMembershipView) setProjectMemberData(event *models.Event) error { - member := new(proj_es_model.ProjectMember) - if err := json.Unmarshal(event.Data, member); err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data") - } - u.UserID = member.UserID - u.Roles = member.Roles - return nil -} - -func (u *UserMembershipView) setProjectGrantMemberData(event *models.Event) error { - member := new(proj_es_model.ProjectGrantMember) - if err := json.Unmarshal(event.Data, member); err != nil { - logging.New().WithError(err).Error("could not unmarshal event data") - return zerrors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data") - } - u.UserID = member.UserID - u.ObjectID = member.GrantID - u.Roles = member.Roles - return nil -} diff --git a/internal/user/repository/view/model/user_membership_query.go b/internal/user/repository/view/model/user_membership_query.go deleted file mode 100644 index 37d68792b6..0000000000 --- a/internal/user/repository/view/model/user_membership_query.go +++ /dev/null @@ -1,70 +0,0 @@ -package model - -import ( - "github.com/zitadel/zitadel/internal/domain" - usr_model "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/view/repository" -) - -type UserMembershipSearchRequest usr_model.UserMembershipSearchRequest -type UserMembershipSearchQuery usr_model.UserMembershipSearchQuery -type UserMembershipSearchKey usr_model.UserMembershipSearchKey - -func (req UserMembershipSearchRequest) GetLimit() uint64 { - return req.Limit -} - -func (req UserMembershipSearchRequest) GetOffset() uint64 { - return req.Offset -} - -func (req UserMembershipSearchRequest) GetSortingColumn() repository.ColumnKey { - if req.SortingColumn == usr_model.UserMembershipSearchKeyUnspecified { - return nil - } - return UserMembershipSearchKey(req.SortingColumn) -} - -func (req UserMembershipSearchRequest) GetAsc() bool { - return req.Asc -} - -func (req UserMembershipSearchRequest) GetQueries() []repository.SearchQuery { - result := make([]repository.SearchQuery, len(req.Queries)) - for i, q := range req.Queries { - result[i] = UserMembershipSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} - } - return result -} - -func (req UserMembershipSearchQuery) GetKey() repository.ColumnKey { - return UserMembershipSearchKey(req.Key) -} - -func (req UserMembershipSearchQuery) GetMethod() domain.SearchMethod { - return req.Method -} - -func (req UserMembershipSearchQuery) GetValue() interface{} { - return req.Value -} - -func (key UserMembershipSearchKey) ToColumnName() string { - switch usr_model.UserMembershipSearchKey(key) { - case usr_model.UserMembershipSearchKeyUserID: - return UserMembershipKeyUserID - case usr_model.UserMembershipSearchKeyResourceOwner: - return UserMembershipKeyResourceOwner - case usr_model.UserMembershipSearchKeyMemberType: - return UserMembershipKeyMemberType - case usr_model.UserMembershipSearchKeyAggregateID: - return UserMembershipKeyAggregateID - case usr_model.UserMembershipSearchKeyObjectID: - return UserMembershipKeyObjectID - case usr_model.UserMembershipSearchKeyInstanceID: - return UserMembershipKeyInstanceID - - default: - return "" - } -} diff --git a/internal/user/repository/view/notify_user.go b/internal/user/repository/view/notify_user.go deleted file mode 100644 index 622a5c4e6a..0000000000 --- a/internal/user/repository/view/notify_user.go +++ /dev/null @@ -1,56 +0,0 @@ -package view - -import ( - "github.com/jinzhu/gorm" - - "github.com/zitadel/zitadel/internal/domain" - usr_model "github.com/zitadel/zitadel/internal/user/model" - "github.com/zitadel/zitadel/internal/user/repository/view/model" - "github.com/zitadel/zitadel/internal/view/repository" - "github.com/zitadel/zitadel/internal/zerrors" -) - -func NotifyUserByID(db *gorm.DB, table, userID, instanceID string) (*model.NotifyUser, error) { - user := new(model.NotifyUser) - query := repository.PrepareGetByQuery(table, - model.NotifyUserSearchQuery{Key: usr_model.NotifyUserSearchKeyUserID, Method: domain.SearchMethodEquals, Value: userID}, - model.NotifyUserSearchQuery{Key: usr_model.NotifyUserSearchKeyInstanceID, Method: domain.SearchMethodEquals, Value: instanceID}, - ) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Gad31", "Errors.User.NotFound") - } - return user, err -} - -func NotifyUsersByOrgID(db *gorm.DB, table, orgID, instanceID string) ([]*model.NotifyUser, error) { - users := make([]*model.NotifyUser, 0) - orgIDQuery := &usr_model.NotifyUserSearchQuery{ - Key: usr_model.NotifyUserSearchKeyResourceOwner, - Method: domain.SearchMethodEquals, - Value: orgID, - } - instanceIDQuery := &usr_model.NotifyUserSearchQuery{ - Key: usr_model.NotifyUserSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - query := repository.PrepareSearchQuery(table, model.NotifyUserSearchRequest{ - Queries: []*usr_model.NotifyUserSearchQuery{orgIDQuery, instanceIDQuery}, - }) - _, err := query(db, &users) - return users, err -} - -func PutNotifyUser(db *gorm.DB, table string, project *model.NotifyUser) error { - save := repository.PrepareSave(table) - return save(db, project) -} - -func DeleteNotifyUser(db *gorm.DB, table, userID, instanceID string) error { - delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.UserSearchKey(usr_model.NotifyUserSearchKeyUserID), userID}, - repository.Key{model.UserSearchKey(usr_model.NotifyUserSearchKeyInstanceID), instanceID}, - ) - return delete(db) -} diff --git a/internal/user/repository/view/user_view.go b/internal/user/repository/view/user_view.go index dcae956540..0b0aeba47d 100644 --- a/internal/user/repository/view/user_view.go +++ b/internal/user/repository/view/user_view.go @@ -36,89 +36,6 @@ func UserByID(db *gorm.DB, table, userID, instanceID string) (*model.UserView, e return user, err } -func UserByUserName(db *gorm.DB, table, userName, instanceID string) (*model.UserView, error) { - user := new(model.UserView) - userNameQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyUserName, - Method: domain.SearchMethodEquals, - Value: userName, - } - instanceIDQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareGetByQuery(table, userNameQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-Lso9s", "Errors.User.NotFound") - } - user.SetEmptyUserType() - return user, err -} - -func UserByLoginName(db *gorm.DB, table, loginName, instanceID string) (*model.UserView, error) { - user := new(model.UserView) - loginNameQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyLoginNames, - Method: domain.SearchMethodListContains, - Value: loginName, - } - instanceIDQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareGetByQuery(table, loginNameQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-AD4qs", "Errors.User.NotFound") - } - user.SetEmptyUserType() - return user, err -} - -func UserByLoginNameAndResourceOwner(db *gorm.DB, table, loginName, resourceOwner, instanceID string) (*model.UserView, error) { - user := new(model.UserView) - loginNameQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyLoginNames, - Method: domain.SearchMethodListContains, - Value: loginName, - } - resourceOwnerQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyResourceOwner, - Method: domain.SearchMethodEquals, - Value: resourceOwner, - } - instanceIDQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchKeyInstanceID, - Method: domain.SearchMethodEquals, - Value: instanceID, - } - ownerRemovedQuery := &model.UserSearchQuery{ - Key: usr_model.UserSearchOwnerRemoved, - Method: domain.SearchMethodEquals, - Value: false, - } - query := repository.PrepareGetByQuery(table, loginNameQuery, resourceOwnerQuery, instanceIDQuery, ownerRemovedQuery) - err := query(db, user) - if zerrors.IsNotFound(err) { - return nil, zerrors.ThrowNotFound(nil, "VIEW-AD4qs", "Errors.User.NotFoundOnOrg") - } - user.SetEmptyUserType() - return user, err -} - func UsersByOrgID(db *gorm.DB, table, orgID, instanceID string) ([]*model.UserView, error) { users := make([]*model.UserView, 0) orgIDQuery := &usr_model.UserSearchQuery{ diff --git a/internal/view/repository/query.go b/internal/view/repository/query.go index b7800fed20..4b931b7d5e 100644 --- a/internal/view/repository/query.go +++ b/internal/view/repository/query.go @@ -95,36 +95,42 @@ func SetQuery(query *gorm.DB, key ColumnKey, value interface{}, method domain.Se if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-SLj7s", "Starts with only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where(column+" LIKE ?", valueText+"%") case domain.SearchMethodStartsWithIgnoreCase: valueText, ok := value.(string) if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-eidus", "Starts with ignore case only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where("LOWER("+column+") LIKE LOWER(?)", valueText+"%") case domain.SearchMethodEndsWith: valueText, ok := value.(string) if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-Hswd3", "Ends with only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where(column+" LIKE ?", "%"+valueText) case domain.SearchMethodEndsWithIgnoreCase: valueText, ok := value.(string) if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-dAG31", "Ends with ignore case only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where("LOWER("+column+") LIKE LOWER(?)", "%"+valueText) case domain.SearchMethodContains: valueText, ok := value.(string) if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-3ids", "Contains with only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where(column+" LIKE ?", "%"+valueText+"%") case domain.SearchMethodContainsIgnoreCase: valueText, ok := value.(string) if !ok { return nil, zerrors.ThrowInvalidArgument(nil, "VIEW-eid73", "Contains with ignore case only possible for strings") } + valueText = database.EscapeLikeWildcards(valueText) query = query.Where("LOWER("+column+") LIKE LOWER(?)", "%"+valueText+"%") case domain.SearchMethodNotEquals: query = query.Where(""+column+" <> ?", value) diff --git a/internal/view/repository/query_test.go b/internal/view/repository/query_test.go index dd068d2b85..49cd961b1a 100644 --- a/internal/view/repository/query_test.go +++ b/internal/view/repository/query_test.go @@ -1,6 +1,7 @@ package repository import ( + "reflect" "testing" "github.com/jinzhu/gorm" @@ -155,3 +156,304 @@ func TestPrepareSearchQuery(t *testing.T) { }) } } + +func TestSetQuery(t *testing.T) { + query := mockDB(t).db.Select("test_field").Table("test_table") + exprPrefix := `(SELECT test_field FROM "test_table" WHERE ` + type args struct { + key ColumnKey + value interface{} + method domain.SearchMethod + } + type want struct { + isErr func(t *testing.T, got error) + query *gorm.SqlExpr + } + tests := []struct { + name string + args args + want want + }{ + { + name: "contains", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodContains, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%asdf%"), + }, + }, + { + name: "contains _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodContains, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%as\\_df%"), + }, + }, + { + name: "contains % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodContains, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%as\\%df%"), + }, + }, + { + name: "contains % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodContains, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%a\\_s\\%d\\_f%"), + }, + }, + { + name: "starts with", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodStartsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "asdf%"), + }, + }, + { + name: "starts with _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodStartsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "as\\_df%"), + }, + }, + { + name: "starts with % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodStartsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "as\\%df%"), + }, + }, + { + name: "starts with % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodStartsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "a\\_s\\%d\\_f%"), + }, + }, + { + name: "ends with", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodEndsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%asdf"), + }, + }, + { + name: "ends with _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodEndsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%as\\_df"), + }, + }, + { + name: "ends with % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodEndsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%as\\%df"), + }, + }, + { + name: "ends with % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodEndsWith, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(test LIKE ?))", "%a\\_s\\%d\\_f"), + }, + }, + { + name: "starts with ignore case", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodStartsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "asdf%"), + }, + }, + { + name: "starts with ignore case _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodStartsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "as\\_df%"), + }, + }, + { + name: "starts with ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodStartsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "as\\%df%"), + }, + }, + { + name: "starts with ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodStartsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "a\\_s\\%d\\_f%"), + }, + }, + { + name: "ends with ignore case", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodEndsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%asdf"), + }, + }, + { + name: "ends with ignore case _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodEndsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%as\\_df"), + }, + }, + { + name: "ends with ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodEndsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%as\\%df"), + }, + }, + { + name: "ends with ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodEndsWithIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%a\\_s\\%d\\_f"), + }, + }, + { + name: "contains ignore case", + args: args{ + key: TestSearchKey_TEST, + value: "asdf", + method: domain.SearchMethodContainsIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%asdf%"), + }, + }, + { + name: "contains ignore case _ wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as_df", + method: domain.SearchMethodContainsIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%as\\_df%"), + }, + }, + { + name: "contains ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "as%df", + method: domain.SearchMethodContainsIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%as\\%df%"), + }, + }, + { + name: "contains ignore case % wildcard", + args: args{ + key: TestSearchKey_TEST, + value: "a_s%d_f", + method: domain.SearchMethodContainsIgnoreCase, + }, + want: want{ + query: gorm.Expr(exprPrefix+"(LOWER(test) LIKE LOWER(?)))", "%a\\_s\\%d\\_f%"), + }, + }, + } + for _, tt := range tests { + if tt.want.isErr == nil { + tt.want.isErr = func(t *testing.T, got error) { + if got == nil { + return + } + t.Errorf("no error expected got: %v", got) + } + } + t.Run(tt.name, func(t *testing.T) { + got, err := SetQuery(query, tt.args.key, tt.args.value, tt.args.method) + tt.want.isErr(t, err) + if !reflect.DeepEqual(got.SubQuery(), tt.want.query) { + t.Errorf("unexpected query: \nwant: %v\n got: %v", *tt.want.query, *got.SubQuery()) + } + }) + } +}