From ab2c3f77526d40e1276b4c887bdd1d20cca4c31c Mon Sep 17 00:00:00 2001 From: mffap Date: Thu, 21 Dec 2023 12:01:11 +0200 Subject: [PATCH 01/12] docs(examples): update examples (#7014) Co-authored-by: Fabi --- docs/docs/examples/introduction.mdx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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). From 5ce542b959a13242db9175383e69628333a5555c Mon Sep 17 00:00:00 2001 From: Silvan Date: Thu, 21 Dec 2023 11:40:51 +0100 Subject: [PATCH 02/12] fix(handler): allow uint32 offset for migration scenarios (#7103) --- internal/eventstore/handler/v2/state.go | 7 ++++--- internal/eventstore/handler/v2/statement.go | 2 +- internal/eventstore/repository/search_query.go | 2 +- internal/eventstore/search_query.go | 8 ++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/internal/eventstore/handler/v2/state.go b/internal/eventstore/handler/v2/state.go index ea674af4c0..cdd9a3b9b9 100644 --- a/internal/eventstore/handler/v2/state.go +++ b/internal/eventstore/handler/v2/state.go @@ -19,7 +19,7 @@ type state struct { aggregateType eventstore.AggregateType aggregateID string sequence uint64 - offset uint16 + offset uint32 } var ( @@ -46,7 +46,7 @@ func (h *Handler) currentState(ctx context.Context, tx *sql.Tx, config *triggerC sequence = new(sql.NullInt64) timestamp = new(sql.NullTime) position = new(sql.NullFloat64) - offset = new(sql.NullInt16) + offset = new(sql.NullInt64) ) stateQuery := currentStateStmt @@ -76,7 +76,8 @@ func (h *Handler) currentState(ctx context.Context, tx *sql.Tx, config *triggerC currentState.sequence = uint64(sequence.Int64) currentState.eventTimestamp = timestamp.Time currentState.position = position.Float64 - currentState.offset = uint16(offset.Int16) + // psql does not provide unsigned numbers so we work around it + currentState.offset = uint32(offset.Int64) return currentState, nil } diff --git a/internal/eventstore/handler/v2/statement.go b/internal/eventstore/handler/v2/statement.go index e1e972c07e..0816d5b451 100644 --- a/internal/eventstore/handler/v2/statement.go +++ b/internal/eventstore/handler/v2/statement.go @@ -65,7 +65,7 @@ type Statement struct { CreationDate time.Time InstanceID string - offset uint16 + offset uint32 Execute Exec } diff --git a/internal/eventstore/repository/search_query.go b/internal/eventstore/repository/search_query.go index 1f35222d7a..3d6d015772 100644 --- a/internal/eventstore/repository/search_query.go +++ b/internal/eventstore/repository/search_query.go @@ -17,7 +17,7 @@ type SearchQuery struct { AllowTimeTravel bool AwaitOpenTransactions bool Limit uint64 - Offset uint16 + Offset uint32 Desc bool InstanceID *Filter diff --git a/internal/eventstore/search_query.go b/internal/eventstore/search_query.go index 27561a1c3b..65facd2c8a 100644 --- a/internal/eventstore/search_query.go +++ b/internal/eventstore/search_query.go @@ -14,7 +14,7 @@ import ( type SearchQueryBuilder struct { columns Columns limit uint64 - offset uint16 + offset uint32 desc bool resourceOwner string instanceID *string @@ -38,7 +38,7 @@ func (b *SearchQueryBuilder) GetLimit() uint64 { return b.limit } -func (b *SearchQueryBuilder) GetOffset() uint16 { +func (b *SearchQueryBuilder) GetOffset() uint32 { return b.offset } @@ -160,7 +160,7 @@ func (builder *SearchQueryBuilder) Matches(commands ...Command) []Command { if builder.limit > 0 && builder.limit <= uint64(len(matches)) { break } - if builder.offset > 0 && uint16(i) < builder.offset { + if builder.offset > 0 && uint32(i) < builder.offset { continue } @@ -213,7 +213,7 @@ func (builder *SearchQueryBuilder) Limit(limit uint64) *SearchQueryBuilder { } // Limit defines how many events are returned maximally. -func (builder *SearchQueryBuilder) Offset(offset uint16) *SearchQueryBuilder { +func (builder *SearchQueryBuilder) Offset(offset uint32) *SearchQueryBuilder { builder.offset = offset return builder } From 85eb2eda0bd17a4bae837dc0ec016c2f20d82db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Thu, 21 Dec 2023 15:57:33 +0200 Subject: [PATCH 03/12] fix(oidc): refresh token for device authorization (#7104) fix(oidc); refresh token for device authorization Due to a mis-alignment of OIDC interface and concrete implementations in zitadel, requesting a refresh token for device authorization would fail. This change adds the possibility to to use the op.IDTokenRequest directly. Also, the UserAgentID is dropped as required parameter, as devices do not have a user agent. --- internal/api/oidc/auth_request.go | 19 +++++++++++-------- internal/command/user_human_refresh_token.go | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index fa99f544a5..062b0e3351 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -200,6 +200,8 @@ func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest) // trigger activity log for authentication for user activity.Trigger(ctx, "", authReq.CurrentAuthRequest.UserID, activity.OIDCAccessToken) return o.command.AddOIDCSessionAccessToken(setContextUserSystem(ctx), authReq.GetID()) + case op.IDTokenRequest: + applicationID = authReq.GetClientID() } accessTokenLifetime, _, _, _, err := o.getOIDCSettings(ctx) @@ -263,15 +265,16 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok } func getInfoFromRequest(req op.TokenRequest) (string, string, string, time.Time, []string) { - authReq, ok := req.(*AuthRequest) - if ok { - return authReq.AgentID, authReq.ApplicationID, authReq.UserOrgID, authReq.AuthTime, authReq.GetAMR() + switch r := req.(type) { + case *AuthRequest: + return r.AgentID, r.ApplicationID, r.UserOrgID, r.AuthTime, r.GetAMR() + case *RefreshTokenRequest: + return r.UserAgentID, r.ClientID, "", r.AuthTime, r.AuthMethodsReferences + case op.IDTokenRequest: + return "", r.GetClientID(), "", r.GetAuthTime(), r.GetAMR() + default: + return "", "", "", time.Time{}, nil } - refreshReq, ok := req.(*RefreshTokenRequest) - if ok { - return refreshReq.UserAgentID, refreshReq.ClientID, "", refreshReq.AuthTime, refreshReq.AuthMethodsReferences - } - return "", "", "", time.Time{}, nil } func (o *OPStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (_ op.RefreshTokenRequest, err error) { diff --git a/internal/command/user_human_refresh_token.go b/internal/command/user_human_refresh_token.go index 6c643f801e..5416cc76d0 100644 --- a/internal/command/user_human_refresh_token.go +++ b/internal/command/user_human_refresh_token.go @@ -45,7 +45,7 @@ func (c *Commands) AddNewRefreshTokenAndAccessToken( refreshIdleExpiration time.Duration, authTime time.Time, ) (accessToken *domain.Token, newRefreshToken string, err error) { - if userID == "" || agentID == "" || clientID == "" { + if userID == "" || clientID == "" { return nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-adg4r", "Errors.IDMissing") } userWriteModel := NewUserWriteModel(userID, orgID) From 3483ec470d95d86c91024e6c79436cd7643693b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Fri, 22 Dec 2023 14:52:01 +0200 Subject: [PATCH 04/12] fix(oidc): ignore unknown language tag in userinfo unmarshal (#7108) This change upgrades oidc to include the fix into zitadel. --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) 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= From 9d5d1cf3ea6226d78090aea07d03affbca6fc2f2 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Thu, 28 Dec 2023 04:25:18 -0500 Subject: [PATCH 05/12] feat: allow glob redirects (#7091) fixes #5110 --- .../api/grpc/oidc/v2/oidc_integration_test.go | 4 +- internal/api/oidc/client_converter.go | 14 ++++++ internal/api/oidc/client_integration_test.go | 4 +- internal/api/oidc/oidc_integration_test.go | 50 ++++++++++++++++++- internal/integration/oidc.go | 14 +++--- 5 files changed, 74 insertions(+), 12 deletions(-) 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/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..1593fbb8e9 100644 --- a/internal/api/oidc/client_integration_test.go +++ b/internal/api/oidc/client_integration_test.go @@ -59,7 +59,7 @@ 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()) + app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) require.NoError(t, err) api, err := Tester.CreateAPIClient(CTX, project.GetId()) require.NoError(t, err) @@ -158,7 +158,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/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/integration/oidc.go b/internal/integration/oidc.go index aaf3ff1e31..e49b4e9c7e 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 } From 45ccdcfa99e533b4740a3cbfba846fc534486cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Thu, 28 Dec 2023 15:31:41 +0200 Subject: [PATCH 06/12] fix(oidc): nil check for client secret (#7115) This fixes a nil pointer panic when client basic auth is attempted on a client without secret in introspection. --- internal/api/oidc/client_integration_test.go | 140 ++++++++++++++----- internal/api/oidc/introspect.go | 13 +- internal/integration/oidc.go | 16 ++- 3 files changed, 128 insertions(+), 41 deletions(-) diff --git a/internal/api/oidc/client_integration_test.go b/internal/api/oidc/client_integration_test.go index 1593fbb8e9..a20e388dca 100644 --- a/internal/api/oidc/client_integration_test.go +++ b/internal/api/oidc/client_integration_test.go @@ -61,46 +61,116 @@ func TestServer_Introspect(t *testing.T) { require.NoError(t, err) app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false) 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()) - 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) { 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/integration/oidc.go b/internal/integration/oidc.go index e49b4e9c7e..16c4c90ae5 100644 --- a/internal/integration/oidc.go +++ b/internal/integration/oidc.go @@ -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 { From 6d3ce8d5ab47a3d3685e18cbed4f260cc9328e87 Mon Sep 17 00:00:00 2001 From: Silvan Date: Sun, 31 Dec 2023 14:03:23 +0100 Subject: [PATCH 07/12] fix(projection): correct type cast of user grant reactivated (#7123) * fix(projection): correct type cast of user grant reactivated * test: correct mapper --- internal/query/projection/user_grant.go | 2 +- internal/query/projection/user_grant_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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{ From cc2dd8b20b775ed44dbee3e3dca9b48d1e2625c6 Mon Sep 17 00:00:00 2001 From: Silvan Date: Sun, 31 Dec 2023 15:30:25 +0100 Subject: [PATCH 08/12] fix(eventstore): increase performance on push (#7125) --- cmd/setup/19.go | 26 ++++++++++++++++++++++ cmd/setup/19.sql | 1 + cmd/setup/config.go | 1 + cmd/setup/setup.go | 3 +++ internal/eventstore/v3/sequence.go | 4 ++-- internal/eventstore/v3/sequence_test.go | 6 ++--- internal/eventstore/v3/sequences_query.sql | 24 +++++--------------- 7 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 cmd/setup/19.go create mode 100644 cmd/setup/19.sql 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/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 From a8b8c89f730ed24315601ca00e050527b5f9ab63 Mon Sep 17 00:00:00 2001 From: Silvan Date: Tue, 2 Jan 2024 14:41:46 +0100 Subject: [PATCH 09/12] perf(query): increase speed of user queries (#7126) (#7128) * perf(query): increase speed of user queries --- internal/query/user_by_id.sql | 5 +++-- internal/query/user_by_login_name.sql | 6 ++++++ internal/query/user_notify_by_id.sql | 5 +++-- internal/query/user_notify_by_login_name.sql | 6 ++++++ 4 files changed, 18 insertions(+), 4 deletions(-) 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 From 4e3936b5bf0d829e9a6df6b52ffb31f89fa9cc82 Mon Sep 17 00:00:00 2001 From: Silvan Date: Tue, 2 Jan 2024 15:03:23 +0100 Subject: [PATCH 10/12] ci: publish sha to docker registry (#7127) --- .github/workflows/build.yml | 2 +- .github/workflows/version.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 From 9892fd92b67a2adc06a53879c75618c66da6d671 Mon Sep 17 00:00:00 2001 From: Silvan Date: Tue, 2 Jan 2024 15:26:31 +0100 Subject: [PATCH 11/12] refactor: cleanup unused code (#7130) * refactor: drop unused code * refactor: drop unused code --- internal/api/grpc/auth/user.go | 36 --- internal/api/grpc/idp/converter.go | 35 --- internal/api/grpc/management/idp_converter.go | 24 -- .../api/grpc/management/user_converter.go | 36 --- internal/api/grpc/member/converter.go | 7 - internal/api/grpc/object/converter.go | 23 -- internal/api/grpc/project/converter.go | 40 --- .../eventsourcing/eventstore/user_session.go | 5 - internal/auth/repository/user_session.go | 1 - internal/cache/bigcache/bigcache_test.go | 223 ------------- internal/cache/bigcache/cache.go | 67 ---- internal/cache/bigcache/config.go | 17 - internal/cache/cache.go | 7 - internal/cache/config.go | 5 - internal/cache/config/config.go | 59 ---- internal/cache/fastcache/config.go | 11 - internal/cache/fastcache/fastcache.go | 57 ---- internal/cache/fastcache/fastcache_test.go | 218 ------------- internal/cache/generate.go | 3 - internal/cache/mock/cache.mock.go | 80 ----- internal/command/unique_constraints_model.go | 295 ------------------ internal/domain/mfa.go | 4 - internal/domain/notification.go | 4 - internal/domain/policy.go | 4 - internal/domain/policy_label.go | 8 - internal/domain/policy_login.go | 10 - internal/domain/project_grant.go | 5 - internal/domain/project_grant_member.go | 11 - internal/domain/provider.go | 8 - internal/domain/step.go | 29 -- .../domain/unique_constraint_migration.go | 9 - internal/domain/user.go | 17 - internal/domain/user_membership.go | 29 -- internal/iam/model/iam.go | 32 -- internal/iam/model/iam_member.go | 18 -- internal/iam/model/idp_config.go | 110 ------- internal/iam/model/idp_config_view.go | 85 ----- internal/iam/model/idp_provider_view.go | 70 ----- internal/iam/model/label_policy.go | 25 -- internal/iam/model/label_policy_view.go | 47 --- internal/iam/model/login_policy.go | 82 ----- internal/iam/model/login_policy_view.go | 129 -------- internal/iam/model/mail_template.go | 17 - internal/iam/model/mail_text.go | 29 -- internal/iam/model/message_text_view.go | 59 ---- internal/iam/model/mfa_view.go | 47 --- internal/iam/model/password_age_policy.go | 13 - .../iam/model/password_age_policy_view.go | 48 --- .../iam/model/password_complexity_policy.go | 58 ---- .../model/password_complexity_policy_view.go | 32 -- internal/iam/model/password_lockout_policy.go | 13 - .../iam/model/password_lockout_policy_view.go | 48 --- internal/iam/model/privacy_policy_view.go | 49 --- .../eventsourcing/model/iam_member.go | 23 -- .../eventsourcing/model/org_iam_policy.go | 9 - .../model/org_iam_policy_test.go | 49 --- .../iam/repository/view/idp_provider_view.go | 143 --------- internal/iam/repository/view/idp_view.go | 88 ------ .../iam/repository/view/model/idp_config.go | 123 -------- .../repository/view/model/idp_config_query.go | 69 ---- .../iam/repository/view/model/idp_provider.go | 87 ------ .../view/model/idp_provider_query.go | 67 ---- .../view/model/label_policy_query.go | 28 -- .../view/model/password_complexity_policy.go | 56 ---- internal/org/model/domain.go | 33 -- .../repository/eventsourcing/model/member.go | 51 --- .../org/repository/eventsourcing/model/org.go | 10 - .../eventsourcing/model/org_test.go | 44 --- internal/project/model/api_config.go | 39 --- internal/project/model/application.go | 19 -- internal/project/model/application_test.go | 171 ---------- internal/project/model/oidc_config.go | 75 ----- .../project/model/org_project_mapping_view.go | 55 ---- internal/project/model/project.go | 65 ---- internal/project/model/project_grant.go | 45 --- .../project/model/project_grant_member.go | 8 - .../model/project_grant_member_view.go | 72 ----- internal/project/model/project_grant_view.go | 90 ------ internal/project/model/project_member.go | 8 - internal/project/model/project_member_view.go | 73 ----- internal/project/model/project_role.go | 4 - internal/project/model/project_role_view.go | 75 ----- internal/project/model/project_view.go | 77 ----- internal/project/model/saml_config.go | 4 - .../repository/view/model/application.go | 231 -------------- .../repository/view/model/application_test.go | 102 ------ .../view/model/org_project_mapping.go | 16 - .../view/model/org_project_mapping_query.go | 67 ---- .../project/repository/view/model/project.go | 81 ----- .../repository/view/model/project_grant.go | 99 ------ .../view/model/project_grant_member.go | 68 ---- .../view/model/project_grant_member_test.go | 62 ---- .../view/model/project_grant_test.go | 90 ------ .../repository/view/model/project_member.go | 66 ---- .../view/model/project_member_test.go | 59 ---- .../repository/view/model/project_test.go | 72 ----- .../view/org_project_mapping_view.go | 70 ----- internal/query/search_query_test.go | 89 ------ internal/user/model/user_view.go | 15 - .../user/repository/view/external_idp_view.go | 147 --------- .../view/model/external_idp_query.go | 69 ---- .../repository/view/model/external_idps.go | 59 ---- .../user/repository/view/model/notify_user.go | 132 -------- .../view/model/notify_user_query.go | 63 ---- .../repository/view/model/notify_user_test.go | 123 -------- .../repository/view/model/user_membership.go | 135 -------- .../view/model/user_membership_query.go | 70 ----- internal/user/repository/view/notify_user.go | 56 ---- internal/user/repository/view/user_view.go | 83 ----- 109 files changed, 6282 deletions(-) delete mode 100644 internal/cache/bigcache/bigcache_test.go delete mode 100644 internal/cache/bigcache/cache.go delete mode 100644 internal/cache/bigcache/config.go delete mode 100644 internal/cache/cache.go delete mode 100644 internal/cache/config.go delete mode 100644 internal/cache/config/config.go delete mode 100644 internal/cache/fastcache/config.go delete mode 100644 internal/cache/fastcache/fastcache.go delete mode 100644 internal/cache/fastcache/fastcache_test.go delete mode 100644 internal/cache/generate.go delete mode 100644 internal/cache/mock/cache.mock.go delete mode 100644 internal/domain/step.go delete mode 100644 internal/domain/unique_constraint_migration.go delete mode 100644 internal/domain/user_membership.go delete mode 100644 internal/iam/model/iam.go delete mode 100644 internal/iam/model/iam_member.go delete mode 100644 internal/iam/model/idp_config.go delete mode 100644 internal/iam/model/idp_config_view.go delete mode 100644 internal/iam/model/idp_provider_view.go delete mode 100644 internal/iam/model/label_policy.go delete mode 100644 internal/iam/model/login_policy_view.go delete mode 100644 internal/iam/model/mail_template.go delete mode 100644 internal/iam/model/mail_text.go delete mode 100644 internal/iam/model/message_text_view.go delete mode 100644 internal/iam/model/mfa_view.go delete mode 100644 internal/iam/model/password_age_policy.go delete mode 100644 internal/iam/model/password_age_policy_view.go delete mode 100644 internal/iam/model/password_complexity_policy.go delete mode 100644 internal/iam/model/password_lockout_policy.go delete mode 100644 internal/iam/model/password_lockout_policy_view.go delete mode 100644 internal/iam/model/privacy_policy_view.go delete mode 100644 internal/iam/repository/eventsourcing/model/iam_member.go delete mode 100644 internal/iam/repository/eventsourcing/model/org_iam_policy_test.go delete mode 100644 internal/iam/repository/view/idp_provider_view.go delete mode 100644 internal/iam/repository/view/idp_view.go delete mode 100644 internal/iam/repository/view/model/idp_config.go delete mode 100644 internal/iam/repository/view/model/idp_config_query.go delete mode 100644 internal/iam/repository/view/model/idp_provider.go delete mode 100644 internal/iam/repository/view/model/idp_provider_query.go delete mode 100644 internal/org/repository/eventsourcing/model/member.go delete mode 100644 internal/project/model/application_test.go delete mode 100644 internal/project/model/org_project_mapping_view.go delete mode 100644 internal/project/model/project_grant_member_view.go delete mode 100644 internal/project/model/project_grant_view.go delete mode 100644 internal/project/model/project_member_view.go delete mode 100644 internal/project/model/project_role_view.go delete mode 100644 internal/project/model/project_view.go delete mode 100644 internal/project/repository/view/model/application.go delete mode 100644 internal/project/repository/view/model/application_test.go delete mode 100644 internal/project/repository/view/model/org_project_mapping.go delete mode 100644 internal/project/repository/view/model/org_project_mapping_query.go delete mode 100644 internal/project/repository/view/model/project.go delete mode 100644 internal/project/repository/view/model/project_grant.go delete mode 100644 internal/project/repository/view/model/project_grant_member.go delete mode 100644 internal/project/repository/view/model/project_grant_member_test.go delete mode 100644 internal/project/repository/view/model/project_grant_test.go delete mode 100644 internal/project/repository/view/model/project_member.go delete mode 100644 internal/project/repository/view/model/project_member_test.go delete mode 100644 internal/project/repository/view/model/project_test.go delete mode 100644 internal/project/repository/view/org_project_mapping_view.go delete mode 100644 internal/user/repository/view/external_idp_view.go delete mode 100644 internal/user/repository/view/model/external_idp_query.go delete mode 100644 internal/user/repository/view/model/external_idps.go delete mode 100644 internal/user/repository/view/model/notify_user.go delete mode 100644 internal/user/repository/view/model/notify_user_query.go delete mode 100644 internal/user/repository/view/model/notify_user_test.go delete mode 100644 internal/user/repository/view/model/user_membership.go delete mode 100644 internal/user/repository/view/model/user_membership_query.go delete mode 100644 internal/user/repository/view/notify_user.go 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/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/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/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/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/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/search_query_test.go b/internal/query/search_query_test.go index ac56eb6eee..a2c1fb1237 100644 --- a/internal/query/search_query_test.go +++ b/internal/query/search_query_test.go @@ -1018,95 +1018,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/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{ From 8bc56f6fe75cbd1a81aa45e89a0443a6dee7ff6f Mon Sep 17 00:00:00 2001 From: Silvan Date: Tue, 2 Jan 2024 16:27:36 +0100 Subject: [PATCH 12/12] fix(query): escape wildcards in text search (#7131) (#7135) * fix(query): escape like wildcards * test: search query wildcards * add do nothing --- .gitignore | 1 + internal/database/database.go | 8 + internal/query/search_query.go | 56 ++-- internal/query/search_query_test.go | 414 +++++++++++++++++++++++-- internal/view/repository/query.go | 6 + internal/view/repository/query_test.go | 302 ++++++++++++++++++ 6 files changed, 736 insertions(+), 51 deletions(-) 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/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/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 a2c1fb1237..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 { 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()) + } + }) + } +}