diff --git a/cmd/zitadel/setup.yaml b/cmd/zitadel/setup.yaml index 1e08acb25a..afc1e547c2 100644 --- a/cmd/zitadel/setup.yaml +++ b/cmd/zitadel/setup.yaml @@ -67,8 +67,6 @@ SetUp: ApplicationType: 'USER_AGENT' AuthMethodType: 'NONE' DevMode: $ZITADEL_CONSOLE_DEV_MODE - Owners: - - 'zitadel-admin@caos.ch' Step2: DefaultPasswordComplexityPolicy: MinLength: 8 diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go index 374ef0c571..62e33421e4 100644 --- a/internal/api/authz/context.go +++ b/internal/api/authz/context.go @@ -23,6 +23,7 @@ type CtxData struct { ProjectID string AgentID string PreferredLanguage string + ResourceOwner string } func (ctxData CtxData) IsZero() bool { @@ -47,7 +48,7 @@ func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *To } } - userID, clientID, agentID, prefLang, err := verifyAccessToken(ctx, token, t, method) + userID, clientID, agentID, prefLang, resourceOwner, err := verifyAccessToken(ctx, token, t, method) if err != nil { return CtxData{}, err } @@ -64,6 +65,7 @@ func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *To ProjectID: projectID, AgentID: agentID, PreferredLanguage: prefLang, + ResourceOwner: resourceOwner, }, nil } diff --git a/internal/api/authz/permissions_test.go b/internal/api/authz/permissions_test.go index 69877fd4cb..eed375bdf5 100644 --- a/internal/api/authz/permissions_test.go +++ b/internal/api/authz/permissions_test.go @@ -15,8 +15,8 @@ type testVerifier struct { grant *Grant } -func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) { - return "userID", "agentID", "de", nil +func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) { + return "userID", "agentID", "de", "orgID", nil } func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) { diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go index 463b7396c2..352bb44c56 100644 --- a/internal/api/authz/token.go +++ b/internal/api/authz/token.go @@ -20,7 +20,7 @@ type TokenVerifier struct { } type authZRepo interface { - VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang string, err error) + VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang, resourceOwner string, err error) VerifierClientID(ctx context.Context, name string) (clientID string, err error) ResolveGrants(ctx context.Context) (grant *Grant, err error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) @@ -31,13 +31,13 @@ func Start(authZRepo authZRepo) (v *TokenVerifier) { return &TokenVerifier{authZRepo: authZRepo} } -func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID, prefLang string, err error) { +func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID, prefLang, resourceOwner string, err error) { clientID, err = v.clientIDFromMethod(ctx, method) if err != nil { - return "", "", "", "", err + return "", "", "", "", "", err } - userID, agentID, prefLang, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID) - return userID, clientID, agentID, prefLang, err + userID, agentID, prefLang, resourceOwner, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID) + return userID, clientID, agentID, prefLang, resourceOwner, err } type client struct { @@ -111,13 +111,13 @@ func (v *TokenVerifier) CheckAuthMethod(method string) (Option, bool) { return authOpt, ok } -func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID, prefLang string, err error) { +func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID, prefLan, resourceOwner string, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() parts := strings.Split(token, BearerPrefix) if len(parts) != 2 { - return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header") + return "", "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header") } return t.VerifyAccessToken(ctx, parts[1], method) } diff --git a/internal/api/authz/token_test.go b/internal/api/authz/token_test.go index 2303e4ac69..7c256086f7 100644 --- a/internal/api/authz/token_test.go +++ b/internal/api/authz/token_test.go @@ -58,7 +58,7 @@ func Test_VerifyAccessToken(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, _, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method) + _, _, _, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method) if tt.wantErr && err == nil { t.Errorf("got wrong result, should get err: actual: %v ", err) } diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index 5bfc3a5e8e..876be9e74f 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -2,9 +2,10 @@ package auth import ( "context" - "github.com/caos/zitadel/internal/api/authz" + "github.com/golang/protobuf/ptypes/empty" + "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/pkg/grpc/auth" ) @@ -71,7 +72,7 @@ func (s *Server) UpdateMyUserProfile(ctx context.Context, request *auth.UpdateUs func (s *Server) ChangeMyUserName(ctx context.Context, request *auth.ChangeUserNameRequest) (*empty.Empty, error) { ctxData := authz.GetCtxData(ctx) - return &empty.Empty{}, s.command.ChangeUsername(ctx, ctxData.OrgID, ctxData.UserID, request.UserName) + return &empty.Empty{}, s.command.ChangeUsername(ctx, ctxData.ResourceOwner, ctxData.UserID, request.UserName) } func (s *Server) ChangeMyUserEmail(ctx context.Context, request *auth.UpdateUserEmailRequest) (*auth.UserEmail, error) { diff --git a/internal/api/grpc/auth/user_converter.go b/internal/api/grpc/auth/user_converter.go index 9b0c10638e..6f39406b26 100644 --- a/internal/api/grpc/auth/user_converter.go +++ b/internal/api/grpc/auth/user_converter.go @@ -3,7 +3,6 @@ package auth import ( "context" "encoding/json" - "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/logging" "github.com/golang/protobuf/ptypes" @@ -15,6 +14,7 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/telemetry/tracing" usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/pkg/grpc/auth" "github.com/caos/zitadel/pkg/grpc/message" ) @@ -103,7 +103,7 @@ func updateProfileToDomain(ctx context.Context, u *auth.UpdateUserProfileRequest logging.Log("GRPC-lk73L").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("language malformed") return &domain.Profile{ - ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID}, + ObjectRoot: ctxToObjectRoot(ctx), FirstName: u.FirstName, LastName: u.LastName, NickName: u.NickName, @@ -148,7 +148,7 @@ func emailViewFromModel(email *usr_model.Email) *auth.UserEmailView { func updateEmailToDomain(ctx context.Context, e *auth.UpdateUserEmailRequest) *domain.Email { return &domain.Email{ - ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID}, + ObjectRoot: ctxToObjectRoot(ctx), EmailAddress: e.Email, } } @@ -189,7 +189,7 @@ func phoneViewFromModel(phone *usr_model.Phone) *auth.UserPhoneView { func updatePhoneToDomain(ctx context.Context, e *auth.UpdateUserPhoneRequest) *domain.Phone { return &domain.Phone{ - ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID}, + ObjectRoot: ctxToObjectRoot(ctx), PhoneNumber: e.Phone, } } @@ -236,7 +236,7 @@ func addressViewFromModel(address *usr_model.Address) *auth.UserAddressView { func updateAddressToModel(ctx context.Context, address *auth.UpdateUserAddressRequest) *usr_model.Address { return &usr_model.Address{ - ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID}, + ObjectRoot: ctxToObjectRoot(ctx), Country: address.Country, StreetAddress: address.StreetAddress, Region: address.Region, @@ -254,7 +254,7 @@ func externalIDPSearchRequestToModel(request *auth.ExternalIDPSearchRequest) *us func externalIDPRemoveToModel(ctx context.Context, idp *auth.ExternalIDPRemoveRequest) *usr_model.ExternalIDP { return &usr_model.ExternalIDP{ - ObjectRoot: models.ObjectRoot{AggregateID: authz.GetCtxData(ctx).UserID}, + ObjectRoot: ctxToObjectRoot(ctx), IDPConfigID: idp.IdpConfigId, UserID: idp.ExternalUserId, } @@ -454,3 +454,11 @@ func webAuthNTokenFromModel(token *usr_model.WebAuthNToken) *auth.WebAuthNToken State: mfaStateFromModel(token.State), } } + +func ctxToObjectRoot(ctx context.Context) models.ObjectRoot { + ctxData := authz.GetCtxData(ctx) + return models.ObjectRoot{ + AggregateID: ctxData.UserID, + ResourceOwner: ctxData.ResourceOwner, + } +} diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index fbc544ad68..bdc23ad29d 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -60,7 +60,7 @@ func (s *Server) CreateUser(ctx context.Context, in *management.CreateUserReques } func (s *Server) DeactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { - user, err := s.command.DeactivateUser(ctx, in.Id) + user, err := s.command.DeactivateUser(ctx, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -68,7 +68,7 @@ func (s *Server) DeactivateUser(ctx context.Context, in *management.UserID) (*ma } func (s *Server) ReactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { - user, err := s.command.ReactivateUser(ctx, in.Id) + user, err := s.command.ReactivateUser(ctx, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -76,7 +76,7 @@ func (s *Server) ReactivateUser(ctx context.Context, in *management.UserID) (*ma } func (s *Server) LockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { - user, err := s.command.LockUser(ctx, in.Id) + user, err := s.command.LockUser(ctx, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func (s *Server) LockUser(ctx context.Context, in *management.UserID) (*manageme } func (s *Server) UnlockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { - user, err := s.command.UnlockUser(ctx, in.Id) + user, err := s.command.UnlockUser(ctx, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -92,12 +92,12 @@ func (s *Server) UnlockUser(ctx context.Context, in *management.UserID) (*manage } func (s *Server) DeleteUser(ctx context.Context, in *management.UserID) (*empty.Empty, error) { - err := s.command.RemoveUser(ctx, in.Id) + err := s.command.RemoveUser(ctx, in.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } func (s *Server) UpdateUserMachine(ctx context.Context, in *management.UpdateMachineRequest) (*management.MachineResponse, error) { - machine, err := s.command.ChangeMachine(ctx, updateMachineToDomain(in)) + machine, err := s.command.ChangeMachine(ctx, updateMachineToDomain(authz.GetCtxData(ctx), in)) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (s *Server) ChangeUserEmail(ctx context.Context, request *management.Update } func (s *Server) ResendEmailVerificationMail(ctx context.Context, in *management.UserID) (*empty.Empty, error) { - err := s.command.CreateHumanEmailVerificationCode(ctx, in.Id) + err := s.command.CreateHumanEmailVerificationCode(ctx, in.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } @@ -162,12 +162,12 @@ func (s *Server) ChangeUserPhone(ctx context.Context, request *management.Update } func (s *Server) RemoveUserPhone(ctx context.Context, userID *management.UserID) (*empty.Empty, error) { - err := s.command.RemoveHumanPhone(ctx, userID.Id) + err := s.command.RemoveHumanPhone(ctx, userID.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } func (s *Server) ResendPhoneVerificationCode(ctx context.Context, in *management.UserID) (*empty.Empty, error) { - err := s.command.CreateHumanPhoneVerificationCode(ctx, in.Id) + err := s.command.CreateHumanPhoneVerificationCode(ctx, in.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } @@ -180,7 +180,7 @@ func (s *Server) GetUserAddress(ctx context.Context, in *management.UserID) (*ma } func (s *Server) UpdateUserAddress(ctx context.Context, request *management.UpdateUserAddressRequest) (*management.UserAddress, error) { - address, err := s.command.ChangeHumanAddress(ctx, updateAddressToDomain(request)) + address, err := s.command.ChangeHumanAddress(ctx, updateAddressToDomain(authz.GetCtxData(ctx), request)) if err != nil { return nil, err } @@ -188,7 +188,7 @@ func (s *Server) UpdateUserAddress(ctx context.Context, request *management.Upda } func (s *Server) SendSetPasswordNotification(ctx context.Context, request *management.SetPasswordNotificationRequest) (*empty.Empty, error) { - err := s.command.RequestSetPassword(ctx, request.Id, notifyTypeToDomain(request.Type)) + err := s.command.RequestSetPassword(ctx, request.Id, authz.GetCtxData(ctx).OrgID, notifyTypeToDomain(request.Type)) return &empty.Empty{}, err } @@ -197,7 +197,7 @@ func (s *Server) SetInitialPassword(ctx context.Context, request *management.Pas } func (s *Server) ResendInitialMail(ctx context.Context, request *management.InitialMailRequest) (*empty.Empty, error) { - return &empty.Empty{}, s.command.ResendInitialMail(ctx, request.Id, request.Email) + return &empty.Empty{}, s.command.ResendInitialMail(ctx, request.Id, request.Email, authz.GetCtxData(ctx).OrgID) } func (s *Server) SearchUserExternalIDPs(ctx context.Context, request *management.ExternalIDPSearchRequest) (*management.ExternalIDPSearchResponse, error) { @@ -209,7 +209,7 @@ func (s *Server) SearchUserExternalIDPs(ctx context.Context, request *management } func (s *Server) RemoveExternalIDP(ctx context.Context, request *management.ExternalIDPRemoveRequest) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanExternalIDP(ctx, externalIDPRemoveToDomain(request)) + return &empty.Empty{}, s.command.RemoveHumanExternalIDP(ctx, externalIDPRemoveToDomain(authz.GetCtxData(ctx), request)) } func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) { @@ -221,11 +221,11 @@ func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*m } func (s *Server) RemoveMfaOTP(ctx context.Context, userID *management.UserID) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanOTP(ctx, userID.Id) + return &empty.Empty{}, s.command.RemoveHumanOTP(ctx, userID.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) RemoveMfaU2F(ctx context.Context, webAuthNTokenID *management.WebAuthNTokenID) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id) + return &empty.Empty{}, s.command.RemoveHumanU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) (_ *management.WebAuthNTokens, err error) { @@ -237,7 +237,7 @@ func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) } func (s *Server) RemovePasswordless(ctx context.Context, id *management.WebAuthNTokenID) (*empty.Empty, error) { - return &empty.Empty{}, s.command.RemoveHumanPasswordless(ctx, id.UserId, id.Id) + return &empty.Empty{}, s.command.RemoveHumanPasswordless(ctx, id.UserId, id.Id, authz.GetCtxData(ctx).OrgID) } func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) { diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go index fbb81b7b70..fe46abe265 100644 --- a/internal/api/grpc/management/user_converter.go +++ b/internal/api/grpc/management/user_converter.go @@ -4,12 +4,14 @@ import ( "encoding/json" "github.com/caos/logging" - "github.com/caos/zitadel/internal/v2/domain" "github.com/golang/protobuf/ptypes" "golang.org/x/text/language" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/structpb" + "github.com/caos/zitadel/internal/api/authz" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/model" usr_model "github.com/caos/zitadel/internal/user/model" @@ -76,9 +78,12 @@ func externalIDPSearchRequestToModel(request *management.ExternalIDPSearchReques } } -func externalIDPRemoveToDomain(idp *management.ExternalIDPRemoveRequest) *domain.ExternalIDP { +func externalIDPRemoveToDomain(ctxData authz.CtxData, idp *management.ExternalIDPRemoveRequest) *domain.ExternalIDP { return &domain.ExternalIDP{ - ObjectRoot: models.ObjectRoot{AggregateID: idp.UserId}, + ObjectRoot: models.ObjectRoot{ + AggregateID: idp.UserId, + ResourceOwner: ctxData.ResourceOwner, + }, IDPConfigID: idp.IdpConfigId, ExternalUserID: idp.ExternalUserId, } @@ -387,9 +392,12 @@ func addressViewFromModel(address *usr_model.Address) *management.UserAddressVie } } -func updateAddressToDomain(address *management.UpdateUserAddressRequest) *domain.Address { +func updateAddressToDomain(ctxData authz.CtxData, address *management.UpdateUserAddressRequest) *domain.Address { return &domain.Address{ - ObjectRoot: models.ObjectRoot{AggregateID: address.Id}, + ObjectRoot: models.ObjectRoot{ + AggregateID: address.Id, + ResourceOwner: ctxData.OrgID, + }, Country: address.Country, StreetAddress: address.StreetAddress, Region: address.Region, diff --git a/internal/api/grpc/management/user_machine_converter.go b/internal/api/grpc/management/user_machine_converter.go index 6b64756a58..afa978a5ed 100644 --- a/internal/api/grpc/management/user_machine_converter.go +++ b/internal/api/grpc/management/user_machine_converter.go @@ -2,15 +2,18 @@ package management import ( "encoding/json" - "github.com/caos/zitadel/internal/v2/domain" "time" + "github.com/caos/zitadel/internal/api/authz" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/logging" + "github.com/golang/protobuf/ptypes" + "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/model" usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/pkg/grpc/management" - "github.com/golang/protobuf/ptypes" ) func machineCreateToDomain(machine *management.CreateMachineRequest) *domain.Machine { @@ -20,9 +23,12 @@ func machineCreateToDomain(machine *management.CreateMachineRequest) *domain.Mac } } -func updateMachineToDomain(machine *management.UpdateMachineRequest) *domain.Machine { +func updateMachineToDomain(ctxData authz.CtxData, machine *management.UpdateMachineRequest) *domain.Machine { return &domain.Machine{ - ObjectRoot: models.ObjectRoot{AggregateID: machine.Id}, + ObjectRoot: models.ObjectRoot{ + AggregateID: machine.Id, + ResourceOwner: ctxData.ResourceOwner, + }, Name: machine.Name, Description: machine.Description, } diff --git a/internal/api/grpc/server/middleware/auth_interceptor_test.go b/internal/api/grpc/server/middleware/auth_interceptor_test.go index 570a4fbd94..671e64f3a8 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor_test.go +++ b/internal/api/grpc/server/middleware/auth_interceptor_test.go @@ -21,8 +21,8 @@ var ( type verifierMock struct{} -func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) { - return "", "", "", nil +func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) { + return "", "", "", "", nil } func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) { return nil, nil diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index a6a0160edf..86bbdf476f 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -6,9 +6,6 @@ import ( "time" "github.com/caos/logging" - usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" - "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" "github.com/caos/zitadel/internal/crypto" @@ -16,6 +13,9 @@ import ( iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" "github.com/caos/zitadel/internal/telemetry/tracing" + usr_model "github.com/caos/zitadel/internal/user/model" + usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + "github.com/caos/zitadel/internal/user/repository/view/model" ) type TokenVerifierRepo struct { @@ -60,37 +60,37 @@ func (repo *TokenVerifierRepo) TokenByID(ctx context.Context, tokenID, userID st return model.TokenViewToModel(token), nil } -func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, prefLang string, err error) { +func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, prefLang, resourceOwner string, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() //TODO: use real key tokenIDSubject, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32])) if err != nil { - return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token") + return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token") } splittedToken := strings.Split(tokenIDSubject, ":") if len(splittedToken) != 2 { - return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-GDg3a", "invalid token") + return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-GDg3a", "invalid token") } token, err := repo.TokenByID(ctx, splittedToken[0], splittedToken[1]) if err != nil { - return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token") + return "", "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token") } if !token.Expiration.After(time.Now().UTC()) { - return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token") + return "", "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token") } projectID, _, err := repo.ProjectIDAndOriginsByClientID(ctx, clientID) if err != nil { - return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-5M9so", "invalid token") + return "", "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-5M9so", "invalid token") } for _, aud := range token.Audience { if clientID == aud || projectID == aud { - return token.UserID, token.UserAgentID, token.PreferredLanguage, nil + return token.UserID, token.UserAgentID, token.PreferredLanguage, token.ResourceOwner, nil } } - return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience") + return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience") } func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) { diff --git a/internal/iam/repository/eventsourcing/iam.go b/internal/iam/repository/eventsourcing/iam.go index ba62d70c52..0b5a128ca9 100644 --- a/internal/iam/repository/eventsourcing/iam.go +++ b/internal/iam/repository/eventsourcing/iam.go @@ -78,7 +78,7 @@ func IAMSetGlobalOrgAggregate(aggCreator *es_models.AggregateCreator, iam *model func IAMSetIamProjectAggregate(aggCreator *es_models.AggregateCreator, iam *model.IAM, projectID string) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if projectID == "" { - return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sjuw3", "Errors.IAM.IamProjectIDMisisng") + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sjuw3", "Errors.IAM.IAMProjectIDMissing") } agg, err := IAMAggregate(ctx, aggCreator, iam) if err != nil { diff --git a/internal/setup/setup.go b/internal/setup/setup.go index c28e98f719..d46aac031d 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -12,26 +12,14 @@ import ( ) const ( - OrgOwnerRole = "ORG_OWNER" - SetupUser = "SETUP" - OIDCResponseTypeCode = "CODE" - OIDCResponseTypeIDToken = "ID_TOKEN" - OIDCResponseTypeToken = "ID_TOKEN TOKEN" - OIDCGrantTypeAuthorizationCode = "AUTHORIZATION_CODE" - OIDCGrantTypeImplicit = "IMPLICIT" - OIDCGrantTypeRefreshToken = "REFRESH_TOKEN" - OIDCApplicationTypeNative = "NATIVE" - OIDCApplicationTypeUserAgent = "USER_AGENT" - OIDCApplicationTypeWeb = "WEB" - OIDCAuthMethodTypeNone = "NONE" - OIDCAuthMethodTypeBasic = "BASIC" - OIDCAuthMethodTypePost = "POST" + OrgOwnerRole = "ORG_OWNER" + SetupUser = "SETUP" ) func Execute(ctx context.Context, setUpConfig IAMSetUp, iamID string, commands *command.CommandSide) error { logging.Log("SETUP-JAK2q").Info("starting setup") - iam, err := commands.GetIAM(ctx, iamID) + iam, err := commands.GetIAM(ctx) if err != nil && !caos_errs.IsNotFound(err) { return err } diff --git a/internal/setup/step1.go b/internal/setup/step1.go deleted file mode 100644 index e74b575dda..0000000000 --- a/internal/setup/step1.go +++ /dev/null @@ -1,291 +0,0 @@ -package setup - -// TODO: implement -//import ( -// "context" -// -// "github.com/caos/logging" -// -// iam_model "github.com/caos/zitadel/internal/iam/model" -// "github.com/caos/zitadel/internal/v2/command" -//) -// -//type Step1 struct { -// //GlobalOrg string -// //IAMProject string -// //DefaultLoginPolicy LoginPolicy -// //Orgs []Org -// //Owners []string -// command.Step1 -// -// //setup *Setup -// //createdUsers map[string]*usr_model.User -// //createdOrgs map[string]*org_model.Org -// //createdProjects map[string]*proj_model.Project -// //pwComplexityPolicy *iam_model.PasswordComplexityPolicyView -//} -// -//func (s *Step1) isNil() bool { -// return s == nil -//} -// -//func (s *Step1) step() iam_model.Step { -// return iam_model.Step1 -//} -// -////func (s *Step1) init(setup *Setup) { -//// s.setup = setup -//// s.createdUsers = make(map[string]*usr_model.User) -//// s.createdOrgs = make(map[string]*org_model.Org) -//// s.createdProjects = make(map[string]*proj_model.Project) -////} -// -//func (s *Step1) execute(ctx context.Context, iamID string, commands command.CommandSide) error { -// err := commands.SetupStep1(ctx, iamID, s.Step1) -// if err != nil { -// logging.Log("SETUP-de342").WithField("step", s.step()).WithError(err).Error("unable to finish setup") -// return err -// } -// return nil -//} - -// -//func (step *Step1) loginPolicy(ctx context.Context, policy LoginPolicy) error { -// logging.Log("SETUP-4djul").Info("setting up login policy") -// loginPolicy := &iam_model.LoginPolicy{ -// ObjectRoot: models.ObjectRoot{ -// AggregateID: step.setup.iamID, -// }, -// AllowRegister: policy.AllowRegister, -// AllowUsernamePassword: policy.AllowUsernamePassword, -// AllowExternalIdp: policy.AllowExternalIdp, -// } -// _, err := step.setup.Commands.AddDefaultLoginPolicy(ctx, loginPolicy) -// return err -//} -// -//func (step *Step1) orgs(ctx context.Context, orgs []Org) error { -// logging.Log("SETUP-dsTh3").Info("setting up orgs") -// for _, iamOrg := range orgs { -// org, err := step.org(ctx, iamOrg) -// if err != nil { -// logging.LogWithFields("SETUP-IlLif", "Org", iamOrg.Name).WithError(err).Error("unable to create org") -// return err -// } -// step.createdOrgs[iamOrg.Name] = org -// logging.LogWithFields("SETUP-HR2gh", "name", org.Name, "ID", org.AggregateID).Info("created organisation") -// -// var policy *iam_model.OrgIAMPolicyView -// if iamOrg.OrgIamPolicy { -// policy, err = step.iamorgpolicy(ctx, org) -// if err != nil { -// logging.LogWithFields("SETUP-IlLif", "Org IAM Policy", iamOrg.Name).WithError(err).Error("unable to create iam org policy") -// return err -// } -// } else { -// policy = &iam_model.OrgIAMPolicyView{ -// UserLoginMustBeDomain: true, -// } -// } -// -// ctx = setSetUpContextData(ctx, org.AggregateID) -// err = step.users(ctx, iamOrg.Users, policy) -// if err != nil { -// logging.LogWithFields("SETUP-8zfwz", "Org", iamOrg.Name).WithError(err).Error("unable to set up org users") -// return err -// } -// -// err = step.orgOwners(ctx, org, iamOrg.Owners) -// if err != nil { -// logging.LogWithFields("SETUP-0874m", "Org", iamOrg.Name).WithError(err).Error("unable to set up org owners") -// return err -// } -// -// err = step.projects(ctx, iamOrg.Projects, step.createdUsers[iamOrg.Owners[0]].AggregateID) -// if err != nil { -// logging.LogWithFields("SETUP-wUzqY", "Org", iamOrg.Name).WithError(err).Error("unable to set up org projects") -// return err -// } -// } -// logging.Log("SETUP-dgjT4").Info("orgs set up") -// return nil -//} -// -//func (step *Step1) org(ctx context.Context, org Org) (*org_model.Org, error) { -// ctx = setSetUpContextData(ctx, "") -// createOrg := &org_model.Org{ -// Name: org.Name, -// Domains: []*org_model.OrgDomain{{Domain: org.Domain}}, -// } -// return step.setup.OrgEvents.CreateOrg(ctx, createOrg, nil) -//} -// -//func (step *Step1) iamorgpolicy(ctx context.Context, org *org_model.Org) (*iam_model.OrgIAMPolicyView, error) { -// ctx = setSetUpContextData(ctx, org.AggregateID) -// policy := &iam_model.OrgIAMPolicy{ -// ObjectRoot: models.ObjectRoot{AggregateID: org.AggregateID}, -// UserLoginMustBeDomain: false, -// } -// createdpolicy, err := step.setup.OrgEvents.AddOrgIAMPolicy(ctx, policy) -// if err != nil { -// return nil, err -// } -// return &iam_model.OrgIAMPolicyView{ -// AggregateID: org.AggregateID, -// UserLoginMustBeDomain: createdpolicy.UserLoginMustBeDomain, -// }, nil -//} -// -//func (step *Step1) iamOwners(ctx context.Context, owners []string) error { -// logging.Log("SETUP-dtxfj").Info("setting iam owners") -// for _, iamOwner := range owners { -// user, ok := step.createdUsers[iamOwner] -// if !ok { -// logging.LogWithFields("SETUP-8siew", "Owner", iamOwner).Error("unable to add user to iam members") -// return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-su6L3", "unable to add user to iam members") -// } -// _, err := step.setup.Commands.AddIAMMember(ctx, &iam_model.IAMMember{ObjectRoot: models.ObjectRoot{AggregateID: step.setup.iamID}, UserID: user.AggregateID, Roles: []string{"IAM_OWNER"}}) -// if err != nil { -// logging.Log("SETUP-LM7rI").WithError(err).Error("unable to add iam administrator to iam members as owner") -// return err -// } -// } -// logging.Log("SETUP-fg5aq").Info("iam owners set") -// return nil -//} -// -//func (step *Step1) setGlobalOrg(ctx context.Context, globalOrgName string) error { -// logging.Log("SETUP-dsj75").Info("setting global org") -// globalOrg, ok := step.createdOrgs[globalOrgName] -// if !ok { -// logging.LogWithFields("SETUP-FBhs9", "GlobalOrg", globalOrgName).Error("global org not created") -// return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-4GwU7", "global org not created: %v", globalOrgName) -// } -// -// if _, err := step.setup.IamEvents.SetGlobalOrg(ctx, step.setup.iamID, globalOrg.AggregateID); err != nil { -// logging.Log("SETUP-uGMA3").WithError(err).Error("unable to set global org on iam") -// return err -// } -// logging.Log("SETUP-d32h1").Info("global org set") -// return nil -//} -// -//func (step *Step1) setIamProject(ctx context.Context, iamProjectName string) error { -// logging.Log("SETUP-HE3qa").Info("setting iam project") -// iamProject, ok := step.createdProjects[iamProjectName] -// if !ok { -// logging.LogWithFields("SETUP-SJFWP", "IAM Project", iamProjectName).Error("iam project created") -// return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-sGmQt", "iam project not created: %v", iamProjectName) -// } -// -// if _, err := step.setup.IamEvents.SetIAMProject(ctx, step.setup.iamID, iamProject.AggregateID); err != nil { -// logging.Log("SETUP-i1pNh").WithError(err).Error("unable to set iam project on iam") -// return err -// } -// logging.Log("SETUP-d7WEU").Info("iam project set") -// return nil -//} -// -//func (step *Step1) users(ctx context.Context, users []User, orgPolicy *iam_model.OrgIAMPolicyView) error { -// for _, user := range users { -// created, err := step.user(ctx, user, orgPolicy) -// if err != nil { -// logging.LogWithFields("SETUP-9soer", "Email", user.Email).WithError(err).Error("unable to create iam user") -// return err -// } -// step.createdUsers[user.Email] = created -// } -// return nil -//} -// -//func (step *Step1) user(ctx context.Context, user User, orgPolicy *iam_model.OrgIAMPolicyView) (*usr_model.User, error) { -// createUser := &usr_model.User{ -// UserName: user.UserName, -// Human: &usr_model.Human{ -// Profile: &usr_model.Profile{ -// FirstName: user.FirstName, -// LastName: user.LastName, -// }, -// Email: &usr_model.Email{ -// EmailAddress: user.Email, -// IsEmailVerified: true, -// }, -// Password: &usr_model.Password{ -// SecretString: user.Password, -// }, -// }, -// } -// return step.setup.UserEvents.CreateUser(ctx, createUser, step.pwComplexityPolicy, orgPolicy) -//} -// -//func (step *Step1) orgOwners(ctx context.Context, org *org_model.Org, owners []string) error { -// for _, orgOwner := range owners { -// user, ok := step.createdUsers[orgOwner] -// if !ok { -// logging.LogWithFields("SETUP-s9ilr", "Owner", orgOwner).Error("unable to add user to org members") -// return caos_errs.ThrowPreconditionFailedf(nil, "SETUP-s0prs", "unable to add user to org members: %v", orgOwner) -// } -// err := step.orgOwner(ctx, org, user) -// if err != nil { -// logging.Log("SETUP-s90oe").WithError(err).Error("unable to add global org admin to members of global org") -// return err -// } -// } -// return nil -//} -// -//func (step *Step1) orgOwner(ctx context.Context, org *org_model.Org, user *usr_model.User) error { -// addMember := &org_model.OrgMember{ -// ObjectRoot: models.ObjectRoot{AggregateID: org.AggregateID}, -// UserID: user.AggregateID, -// Roles: []string{OrgOwnerRole}, -// } -// _, err := step.setup.OrgEvents.AddOrgMember(ctx, addMember) -// return err -//} -// -//func (step *Step1) projects(ctx context.Context, projects []Project, ownerID string) error { -// ctxData := authz.GetCtxData(ctx) -// ctxData.UserID = ownerID -// projectCtx := authz.SetCtxData(ctx, ctxData) -// -// for _, project := range projects { -// createdProject, err := step.project(projectCtx, project) -// if err != nil { -// return err -// } -// step.createdProjects[createdProject.Name] = createdProject -// for _, oidc := range project.OIDCApps { -// app, err := step.oidcApp(ctx, createdProject, oidc) -// if err != nil { -// return err -// } -// logging.LogWithFields("SETUP-asd32f", "name", app.Name, "clientID", app.OIDCConfig.ClientID).Info("created OIDC application") -// } -// } -// return nil -//} -// -//func (step *Step1) project(ctx context.Context, project Project) (*proj_model.Project, error) { -// addProject := &proj_model.Project{ -// Name: project.Name, -// } -// return step.setup.ProjectEvents.CreateProject(ctx, addProject, false) -//} -// -//func (step *Step1) oidcApp(ctx context.Context, project *proj_model.Project, oidc OIDCApp) (*proj_model.Application, error) { -// addOIDCApp := &proj_model.Application{ -// ObjectRoot: models.ObjectRoot{AggregateID: project.AggregateID}, -// Name: oidc.Name, -// OIDCConfig: &proj_model.OIDCConfig{ -// RedirectUris: oidc.RedirectUris, -// ResponseTypes: getOIDCResponseTypes(oidc.ResponseTypes), -// GrantTypes: getOIDCGrantTypes(oidc.GrantTypes), -// ApplicationType: getOIDCApplicationType(oidc.ApplicationType), -// AuthMethodType: getOIDCAuthMethod(oidc.AuthMethodType), -// PostLogoutRedirectUris: oidc.PostLogoutRedirectUris, -// DevMode: oidc.DevMode, -// }, -// } -// return step.setup.ProjectEvents.AddApplication(ctx, addOIDCApp) -//} diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 8bf48d0304..bc790a76d2 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -185,7 +185,9 @@ Errors: MemberNotExisting: Member existiert nicht IDMissing: Id fehlt GlobalOrgMissing: Globale Organisation fehlt - IamProjectIDMisisng: Iam Project ID fehlt + GlobalOrgAlreadySet: Globale Organisation wurde bereits gesetzt + IAMProjectIDMissing: IAM Project ID fehlt + IamProjectAlreadySet: IAM Project ID wurde bereits gesetzt IdpInvalid: IDP Konfiguration ist ungültig IdpNotExisting: IDP Konfiguration existiert nicht OIDCConfigInvalid: OIDC IDP Konfiguration ist ungültig diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 93512dcfed..42c09a2928 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -185,7 +185,9 @@ Errors: MemberNotExisting: Member does not exist IDMissing: Id missing GlobalOrgMissing: Global organisation missing - IamProjectIDMisisng: Iam project id missing + GlobalOrgAlreadySet: Global organisation has already been set + IAMProjectIDMissing: IAM project id missing + IamProjectAlreadySet: IAM project id has already been set IdpInvalid: IDP configuration is invalid IdpNotExisting: IDP configuration does not exist OIDCConfigInvalid: OIDC IDP configuration is invalid diff --git a/internal/v2/command/command.go b/internal/v2/command/command.go index 58bff3ba28..cae4e5c7ae 100644 --- a/internal/v2/command/command.go +++ b/internal/v2/command/command.go @@ -14,18 +14,18 @@ import ( type CommandSide struct { eventstore *eventstore.Eventstore idGenerator id.Generator - iamID string iamDomain string idpConfigSecretCrypto crypto.Crypto - userPasswordAlg crypto.HashAlgorithm - initializeUserCode crypto.Generator - emailVerificationCode crypto.Generator - phoneVerificationCode crypto.Generator - passwordVerificationCode crypto.Generator - machineKeyAlg crypto.EncryptionAlgorithm - machineKeySize int + userPasswordAlg crypto.HashAlgorithm + initializeUserCode crypto.Generator + emailVerificationCode crypto.Generator + phoneVerificationCode crypto.Generator + passwordVerificationCode crypto.Generator + machineKeyAlg crypto.EncryptionAlgorithm + machineKeySize int + applicationSecretGenerator crypto.Generator } type Config struct { @@ -37,34 +37,37 @@ func StartCommandSide(config *Config) (repo *CommandSide, err error) { repo = &CommandSide{ eventstore: config.Eventstore, idGenerator: id.SonyFlakeGenerator, - iamID: config.SystemDefaults.IamID, iamDomain: config.SystemDefaults.Domain, } iam_repo.RegisterEventMappers(repo.eventstore) + //TODO: simplify!!!! repo.idpConfigSecretCrypto, err = crypto.NewAESCrypto(config.SystemDefaults.IDPConfigVerificationKey) if err != nil { return nil, err } - aesCrypto, err := crypto.NewAESCrypto(config.SystemDefaults.UserVerificationKey) + userEncryptionAlgorithm, err := crypto.NewAESCrypto(config.SystemDefaults.UserVerificationKey) if err != nil { return nil, err } - repo.initializeUserCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.InitializeUserCode, aesCrypto) - repo.emailVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.EmailVerificationCode, aesCrypto) - repo.phoneVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PhoneVerificationCode, aesCrypto) - repo.passwordVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto) + repo.initializeUserCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.InitializeUserCode, userEncryptionAlgorithm) + repo.emailVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.EmailVerificationCode, userEncryptionAlgorithm) + repo.phoneVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PhoneVerificationCode, userEncryptionAlgorithm) + repo.passwordVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PasswordVerificationCode, userEncryptionAlgorithm) repo.userPasswordAlg = crypto.NewBCrypt(config.SystemDefaults.SecretGenerators.PasswordSaltCost) - repo.machineKeyAlg = aesCrypto + repo.machineKeyAlg = userEncryptionAlgorithm repo.machineKeySize = int(config.SystemDefaults.SecretGenerators.MachineKeySize) + + passwordAlg := crypto.NewBCrypt(config.SystemDefaults.SecretGenerators.PasswordSaltCost) + repo.applicationSecretGenerator = crypto.NewHashGenerator(config.SystemDefaults.SecretGenerators.ClientSecretGenerator, passwordAlg) return repo, nil } -func (r *CommandSide) iamByID(ctx context.Context, id string) (_ *IAMWriteModel, err error) { +func (r *CommandSide) getIAMWriteModel(ctx context.Context) (_ *IAMWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMWriteModel(id) + writeModel := NewIAMWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam.go b/internal/v2/command/iam.go index 9488ad0c50..9bb3b921cc 100644 --- a/internal/v2/command/iam.go +++ b/internal/v2/command/iam.go @@ -3,15 +3,41 @@ package command import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/iam" ) //TODO: private -func (r *CommandSide) GetIAM(ctx context.Context, aggregateID string) (*domain.IAM, error) { - iamWriteModel := NewIAMWriteModel(aggregateID) +func (r *CommandSide) GetIAM(ctx context.Context) (*domain.IAM, error) { + iamWriteModel := NewIAMWriteModel() err := r.eventstore.FilterToQueryReducer(ctx, iamWriteModel) if err != nil { return nil, err } return writeModelToIAM(iamWriteModel), nil } + +func (r *CommandSide) setGlobalOrg(ctx context.Context, iamAgg *iam.Aggregate, iamWriteModel *IAMWriteModel, orgID string) error { + err := r.eventstore.FilterToQueryReducer(ctx, iamWriteModel) + if err != nil { + return err + } + if iamWriteModel.GlobalOrgID != "" { + return caos_errs.ThrowPreconditionFailed(nil, "IAM-HGG24", "Errors.IAM.GlobalOrgAlreadySet") + } + iamAgg.PushEvents(iam.NewGlobalOrgSetEventEvent(ctx, orgID)) + return nil +} + +func (r *CommandSide) setIAMProject(ctx context.Context, iamAgg *iam.Aggregate, iamWriteModel *IAMWriteModel, projectID string) error { + err := r.eventstore.FilterToQueryReducer(ctx, iamWriteModel) + if err != nil { + return err + } + if iamWriteModel.ProjectID != "" { + return caos_errs.ThrowPreconditionFailed(nil, "IAM-EGbw2", "Errors.IAM.IAMProjectAlreadySet") + } + iamAgg.PushEvents(iam.NewIAMProjectSetEvent(ctx, projectID)) + return nil +} diff --git a/internal/v2/command/iam_idp_config.go b/internal/v2/command/iam_idp_config.go index 2a1f256c7c..2b47ad27fb 100644 --- a/internal/v2/command/iam_idp_config.go +++ b/internal/v2/command/iam_idp_config.go @@ -22,7 +22,7 @@ func (r *CommandSide) AddDefaultIDPConfig(ctx context.Context, config *domain.ID return nil, err } //TODO: check name unique on aggregate - addedConfig := NewIAMIDPConfigWriteModel(config.AggregateID, idpConfigID) + addedConfig := NewIAMIDPConfigWriteModel(idpConfigID) clientSecret, err := crypto.Crypt([]byte(config.OIDCConfig.ClientSecretString), r.idpConfigSecretCrypto) if err != nil { @@ -58,7 +58,7 @@ func (r *CommandSide) AddDefaultIDPConfig(ctx context.Context, config *domain.ID } func (r *CommandSide) ChangeDefaultIDPConfig(ctx context.Context, config *domain.IDPConfig) (*domain.IDPConfig, error) { - existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, config.AggregateID, config.IDPConfigID) + existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, config.IDPConfigID) if err != nil { return nil, err } @@ -81,7 +81,7 @@ func (r *CommandSide) ChangeDefaultIDPConfig(ctx context.Context, config *domain } func (r *CommandSide) DeactivateDefaultIDPConfig(ctx context.Context, idpID string) (*domain.IDPConfig, error) { - existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, r.iamID, idpID) + existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, idpID) if err != nil { return nil, err } @@ -99,7 +99,7 @@ func (r *CommandSide) DeactivateDefaultIDPConfig(ctx context.Context, idpID stri } func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID string) (*domain.IDPConfig, error) { - existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, r.iamID, idpID) + existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, idpID) if err != nil { return nil, err } @@ -117,8 +117,8 @@ func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID stri return writeModelToIDPConfig(existingIDP), nil } -func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, iamID, idpID string) (*domain.IDPConfig, error) { - writeModel, err := r.pushDefaultIDPWriteModel(ctx, iamID, idpID, func(a *iam.Aggregate, _ *IAMIDPConfigWriteModel) *iam.Aggregate { +func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string) (*domain.IDPConfig, error) { + writeModel, err := r.pushDefaultIDPWriteModel(ctx, idpID, func(a *iam.Aggregate, _ *IAMIDPConfigWriteModel) *iam.Aggregate { a.Aggregate = *a.PushEvents(iam_repo.NewIDPConfigRemovedEvent(ctx, idpID)) return a }) @@ -129,8 +129,8 @@ func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, iamID, idpID s return writeModelToIDPConfig(writeModel), nil } -func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, iamID, idpID string, eventSetter func(*iam.Aggregate, *IAMIDPConfigWriteModel) *iam.Aggregate) (*IAMIDPConfigWriteModel, error) { - writeModel := NewIAMIDPConfigWriteModel(iamID, idpID) +func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, idpID string, eventSetter func(*iam.Aggregate, *IAMIDPConfigWriteModel) *iam.Aggregate) (*IAMIDPConfigWriteModel, error) { + writeModel := NewIAMIDPConfigWriteModel(idpID) err := r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err @@ -145,11 +145,11 @@ func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, iamID, idpID return writeModel, nil } -func (r *CommandSide) iamIDPConfigWriteModelByID(ctx context.Context, iamID, idpID string) (policy *IAMIDPConfigWriteModel, err error) { +func (r *CommandSide) iamIDPConfigWriteModelByID(ctx context.Context, idpID string) (policy *IAMIDPConfigWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMIDPConfigWriteModel(iamID, idpID) + writeModel := NewIAMIDPConfigWriteModel(idpID) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_idp_config_model.go b/internal/v2/command/iam_idp_config_model.go index 49445de46e..c7523b5bee 100644 --- a/internal/v2/command/iam_idp_config_model.go +++ b/internal/v2/command/iam_idp_config_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" @@ -11,11 +12,12 @@ type IAMIDPConfigWriteModel struct { IDPConfigWriteModel } -func NewIAMIDPConfigWriteModel(iamID, configID string) *IAMIDPConfigWriteModel { +func NewIAMIDPConfigWriteModel(configID string) *IAMIDPConfigWriteModel { return &IAMIDPConfigWriteModel{ IDPConfigWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, ConfigID: configID, }, @@ -24,7 +26,8 @@ func NewIAMIDPConfigWriteModel(iamID, configID string) *IAMIDPConfigWriteModel { func (wm *IAMIDPConfigWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMIDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) { diff --git a/internal/v2/command/iam_idp_oidc_config.go b/internal/v2/command/iam_idp_oidc_config.go index d757916429..fe6b0eb5db 100644 --- a/internal/v2/command/iam_idp_oidc_config.go +++ b/internal/v2/command/iam_idp_oidc_config.go @@ -7,7 +7,7 @@ import ( ) func (r *CommandSide) ChangeDefaultIDPOIDCConfig(ctx context.Context, config *domain.OIDCIDPConfig) (*domain.OIDCIDPConfig, error) { - existingConfig := NewIDPOIDCConfigWriteModel(config.AggregateID, config.IDPConfigID) + existingConfig := NewIAMIDPOIDCConfigWriteModel(config.IDPConfigID) err := r.eventstore.FilterToQueryReducer(ctx, existingConfig) if err != nil { return nil, err diff --git a/internal/v2/command/iam_idp_oidc_config_model.go b/internal/v2/command/iam_idp_oidc_config_model.go index 247dc32892..0c4be89b8f 100644 --- a/internal/v2/command/iam_idp_oidc_config_model.go +++ b/internal/v2/command/iam_idp_oidc_config_model.go @@ -2,22 +2,24 @@ package command import ( "context" + "reflect" + "github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" - "reflect" ) type IDPOIDCConfigWriteModel struct { OIDCConfigWriteModel } -func NewIDPOIDCConfigWriteModel(iamID, idpConfigID string) *IDPOIDCConfigWriteModel { +func NewIAMIDPOIDCConfigWriteModel(idpConfigID string) *IDPOIDCConfigWriteModel { return &IDPOIDCConfigWriteModel{ OIDCConfigWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, IDPConfigID: idpConfigID, }, @@ -67,7 +69,8 @@ func (wm *IDPOIDCConfigWriteModel) Reduce() error { func (wm *IDPOIDCConfigWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IDPOIDCConfigWriteModel) NewChangedEvent( diff --git a/internal/v2/command/iam_member.go b/internal/v2/command/iam_member.go index cc24835706..da078f7787 100644 --- a/internal/v2/command/iam_member.go +++ b/internal/v2/command/iam_member.go @@ -2,33 +2,22 @@ package command import ( "context" - "github.com/caos/zitadel/internal/v2/domain" "reflect" "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/telemetry/tracing" + "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" ) func (r *CommandSide) AddIAMMember(ctx context.Context, member *domain.Member) (*domain.Member, error) { - //TODO: check if roles valid - - if !member.IsValid() { - return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-W8m4l", "Errors.IAM.MemberInvalid") - } - - addedMember := NewIAMMemberWriteModel(member.AggregateID, member.UserID) - err := r.eventstore.FilterToQueryReducer(ctx, addedMember) + addedMember := NewIAMMemberWriteModel(member.UserID) + iamAgg := IAMAggregateFromWriteModel(&addedMember.MemberWriteModel.WriteModel) + err := r.addIAMMember(ctx, iamAgg, addedMember, member) if err != nil { return nil, err } - if addedMember.State == domain.MemberStateActive { - return nil, errors.ThrowAlreadyExists(nil, "IAM-PtXi1", "Errors.IAM.Member.AlreadyExists") - } - - iamAgg := IAMAggregateFromWriteModel(&addedMember.MemberWriteModel.WriteModel) - iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, member.UserID, member.Roles...)) err = r.eventstore.PushAggregate(ctx, addedMember, iamAgg) if err != nil { @@ -38,6 +27,26 @@ func (r *CommandSide) AddIAMMember(ctx context.Context, member *domain.Member) ( return memberWriteModelToMember(&addedMember.MemberWriteModel), nil } +func (r *CommandSide) addIAMMember(ctx context.Context, iamAgg *iam_repo.Aggregate, addedMember *IAMMemberWriteModel, member *domain.Member) error { + //TODO: check if roles valid + + if !member.IsValid() { + return caos_errs.ThrowPreconditionFailed(nil, "IAM-GR34U", "Errors.IAM.MemberInvalid") + } + + err := r.eventstore.FilterToQueryReducer(ctx, addedMember) + if err != nil { + return err + } + if addedMember.State == domain.MemberStateActive { + return errors.ThrowAlreadyExists(nil, "IAM-sdgQ4", "Errors.IAM.Member.AlreadyExists") + } + + iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, member.UserID, member.Roles...)) + + return nil +} + //ChangeIAMMember updates an existing member func (r *CommandSide) ChangeIAMMember(ctx context.Context, member *domain.Member) (*domain.Member, error) { //TODO: check if roles valid @@ -46,7 +55,7 @@ func (r *CommandSide) ChangeIAMMember(ctx context.Context, member *domain.Member return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-LiaZi", "Errors.IAM.MemberInvalid") } - existingMember, err := r.iamMemberWriteModelByID(ctx, member.AggregateID, member.UserID) + existingMember, err := r.iamMemberWriteModelByID(ctx, member.UserID) if err != nil { return nil, err } @@ -71,7 +80,7 @@ func (r *CommandSide) ChangeIAMMember(ctx context.Context, member *domain.Member } func (r *CommandSide) RemoveIAMMember(ctx context.Context, userID string) error { - m, err := r.iamMemberWriteModelByID(ctx, r.iamID, userID) + m, err := r.iamMemberWriteModelByID(ctx, userID) if err != nil && !errors.IsNotFound(err) { return err } @@ -85,11 +94,11 @@ func (r *CommandSide) RemoveIAMMember(ctx context.Context, userID string) error return r.eventstore.PushAggregate(ctx, m, iamAgg) } -func (r *CommandSide) iamMemberWriteModelByID(ctx context.Context, iamID, userID string) (member *IAMMemberWriteModel, err error) { +func (r *CommandSide) iamMemberWriteModelByID(ctx context.Context, userID string) (member *IAMMemberWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMMemberWriteModel(iamID, userID) + writeModel := NewIAMMemberWriteModel(userID) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_member_model.go b/internal/v2/command/iam_member_model.go index 67519de626..4b6998300f 100644 --- a/internal/v2/command/iam_member_model.go +++ b/internal/v2/command/iam_member_model.go @@ -2,6 +2,7 @@ package command import ( "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -9,11 +10,12 @@ type IAMMemberWriteModel struct { MemberWriteModel } -func NewIAMMemberWriteModel(iamID, userID string) *IAMMemberWriteModel { +func NewIAMMemberWriteModel(userID string) *IAMMemberWriteModel { return &IAMMemberWriteModel{ MemberWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, UserID: userID, }, @@ -48,5 +50,5 @@ func (wm *IAMMemberWriteModel) Reduce() error { func (wm *IAMMemberWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.MemberWriteModel.AggregateID) + AggregateIDs(wm.MemberWriteModel.AggregateID).ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/iam_model.go b/internal/v2/command/iam_model.go index ade81654ce..b7dcbfc4e9 100644 --- a/internal/v2/command/iam_model.go +++ b/internal/v2/command/iam_model.go @@ -16,10 +16,11 @@ type IAMWriteModel struct { ProjectID string } -func NewIAMWriteModel(iamID string) *IAMWriteModel { +func NewIAMWriteModel() *IAMWriteModel { return &IAMWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, } } @@ -56,7 +57,8 @@ func (wm *IAMWriteModel) Reduce() error { func (wm *IAMWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } // diff --git a/internal/v2/command/iam_policy_label.go b/internal/v2/command/iam_policy_label.go index abf18209b0..070d5330c0 100644 --- a/internal/v2/command/iam_policy_label.go +++ b/internal/v2/command/iam_policy_label.go @@ -9,8 +9,7 @@ import ( ) func (r *CommandSide) AddDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMLabelPolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMLabelPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel) err := r.addDefaultLabelPolicy(ctx, nil, addedPolicy, policy) if err != nil { @@ -40,8 +39,7 @@ func (r *CommandSide) addDefaultLabelPolicy(ctx context.Context, iamAgg *iam_rep } func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) { - policy.AggregateID = r.iamID - existingPolicy, err := r.defaultLabelPolicyWriteModelByID(ctx, policy.AggregateID) + existingPolicy, err := r.defaultLabelPolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -66,11 +64,11 @@ func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *doma return writeModelToLabelPolicy(existingPolicy), nil } -func (r *CommandSide) defaultLabelPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMLabelPolicyWriteModel, err error) { +func (r *CommandSide) defaultLabelPolicyWriteModelByID(ctx context.Context) (policy *IAMLabelPolicyWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMLabelPolicyWriteModel(iamID) + writeModel := NewIAMLabelPolicyWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_policy_label_model.go b/internal/v2/command/iam_policy_label_model.go index 096eab1ccc..41cfae9edf 100644 --- a/internal/v2/command/iam_policy_label_model.go +++ b/internal/v2/command/iam_policy_label_model.go @@ -2,7 +2,9 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -10,11 +12,12 @@ type IAMLabelPolicyWriteModel struct { LabelPolicyWriteModel } -func NewIAMLabelPolicyWriteModel(iamID string) *IAMLabelPolicyWriteModel { +func NewIAMLabelPolicyWriteModel() *IAMLabelPolicyWriteModel { return &IAMLabelPolicyWriteModel{ LabelPolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -37,7 +40,8 @@ func (wm *IAMLabelPolicyWriteModel) Reduce() error { func (wm *IAMLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.LabelPolicyWriteModel.AggregateID) + AggregateIDs(wm.LabelPolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMLabelPolicyWriteModel) NewChangedEvent( diff --git a/internal/v2/command/iam_policy_login.go b/internal/v2/command/iam_policy_login.go index 3497f450ec..1dcb4799c9 100644 --- a/internal/v2/command/iam_policy_login.go +++ b/internal/v2/command/iam_policy_login.go @@ -11,7 +11,7 @@ import ( ) func (r *CommandSide) GetDefaultLoginPolicy(ctx context.Context) (*domain.LoginPolicy, error) { - policyWriteModel := NewIAMLoginPolicyWriteModel(r.iamID) + policyWriteModel := NewIAMLoginPolicyWriteModel() err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel) if err != nil { return nil, err @@ -22,8 +22,7 @@ func (r *CommandSide) GetDefaultLoginPolicy(ctx context.Context) (*domain.LoginP } func (r *CommandSide) AddDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMLoginPolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMLoginPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel) err := r.addDefaultLoginPolicy(ctx, nil, addedPolicy, policy) if err != nil { @@ -52,8 +51,7 @@ func (r *CommandSide) addDefaultLoginPolicy(ctx context.Context, iamAgg *iam_rep } func (r *CommandSide) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) { - policy.AggregateID = r.iamID - existingPolicy := NewIAMLoginPolicyWriteModel(r.iamID) + existingPolicy := NewIAMLoginPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel) err := r.changeDefaultLoginPolicy(ctx, iamAgg, existingPolicy, policy) if err != nil { @@ -68,7 +66,6 @@ func (r *CommandSide) ChangeDefaultLoginPolicy(ctx context.Context, policy *doma } func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, existingPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) error { - policy.AggregateID = r.iamID err := r.defaultLoginPolicyWriteModelByID(ctx, existingPolicy) if err != nil { return err @@ -86,8 +83,7 @@ func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *iam_ } func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) (*domain.IDPProvider, error) { - idpProvider.AggregateID = r.iamID - idpModel := NewIAMIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID) + idpModel := NewIAMIdentityProviderWriteModel(idpProvider.IDPConfigID) err := r.eventstore.FilterToQueryReducer(ctx, idpModel) if err != nil { return nil, err @@ -107,8 +103,7 @@ func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, id } func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) error { - idpProvider.AggregateID = r.iamID - idpModel := NewIAMIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID) + idpModel := NewIAMIdentityProviderWriteModel(idpProvider.IDPConfigID) err := r.eventstore.FilterToQueryReducer(ctx, idpModel) if err != nil { return err @@ -123,7 +118,7 @@ func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Contex } func (r *CommandSide) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) (iam_model.SecondFactorType, error) { - secondFactorModel := NewIAMSecondFactorWriteModel(r.iamID) + secondFactorModel := NewIAMSecondFactorWriteModel() iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel) err := r.addSecondFactorToDefaultLoginPolicy(ctx, nil, secondFactorModel, secondFactor) if err != nil { @@ -153,7 +148,7 @@ func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, i } func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) error { - secondFactorModel := NewIAMSecondFactorWriteModel(r.iamID) + secondFactorModel := NewIAMSecondFactorWriteModel() err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel) if err != nil { return err @@ -168,7 +163,7 @@ func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Conte } func (r *CommandSide) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor iam_model.MultiFactorType) (iam_model.MultiFactorType, error) { - multiFactorModel := NewIAMMultiFactorWriteModel(r.iamID) + multiFactorModel := NewIAMMultiFactorWriteModel() iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel) err := r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, multiFactor) if err != nil { @@ -197,7 +192,7 @@ func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, ia } func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor iam_model.MultiFactorType) error { - multiFactorModel := NewIAMMultiFactorWriteModel(r.iamID) + multiFactorModel := NewIAMMultiFactorWriteModel() err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel) if err != nil { return err diff --git a/internal/v2/command/iam_policy_login_factors_model.go b/internal/v2/command/iam_policy_login_factors_model.go index d8aa092e8b..cf85cca0af 100644 --- a/internal/v2/command/iam_policy_login_factors_model.go +++ b/internal/v2/command/iam_policy_login_factors_model.go @@ -2,6 +2,7 @@ package command import ( "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -9,11 +10,12 @@ type IAMSecondFactorWriteModel struct { SecondFactorWriteModel } -func NewIAMSecondFactorWriteModel(iamID string) *IAMSecondFactorWriteModel { +func NewIAMSecondFactorWriteModel() *IAMSecondFactorWriteModel { return &IAMSecondFactorWriteModel{ SecondFactorWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -34,18 +36,20 @@ func (wm *IAMSecondFactorWriteModel) Reduce() error { func (wm *IAMSecondFactorWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.WriteModel.AggregateID) + AggregateIDs(wm.WriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } type IAMMultiFactorWriteModel struct { MultiFactoryWriteModel } -func NewIAMMultiFactorWriteModel(iamID string) *IAMMultiFactorWriteModel { +func NewIAMMultiFactorWriteModel() *IAMMultiFactorWriteModel { return &IAMMultiFactorWriteModel{ MultiFactoryWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -66,5 +70,6 @@ func (wm *IAMMultiFactorWriteModel) Reduce() error { func (wm *IAMMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.WriteModel.AggregateID) + AggregateIDs(wm.WriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/iam_policy_login_identity_provider_model.go b/internal/v2/command/iam_policy_login_identity_provider_model.go index 5c04266933..77d31ed6b2 100644 --- a/internal/v2/command/iam_policy_login_identity_provider_model.go +++ b/internal/v2/command/iam_policy_login_identity_provider_model.go @@ -2,6 +2,7 @@ package command import ( "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -9,11 +10,12 @@ type IAMIdentityProviderWriteModel struct { IdentityProviderWriteModel } -func NewIAMIdentityProviderWriteModel(iamID, idpConfigID string) *IAMIdentityProviderWriteModel { +func NewIAMIdentityProviderWriteModel(idpConfigID string) *IAMIdentityProviderWriteModel { return &IAMIdentityProviderWriteModel{ IdentityProviderWriteModel: IdentityProviderWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, IDPConfigID: idpConfigID, }, @@ -38,5 +40,6 @@ func (wm *IAMIdentityProviderWriteModel) Reduce() error { func (wm *IAMIdentityProviderWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/iam_policy_login_model.go b/internal/v2/command/iam_policy_login_model.go index e29185df0a..6ecfcc90c6 100644 --- a/internal/v2/command/iam_policy_login_model.go +++ b/internal/v2/command/iam_policy_login_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" @@ -11,11 +12,12 @@ type IAMLoginPolicyWriteModel struct { LoginPolicyWriteModel } -func NewIAMLoginPolicyWriteModel(iamID string) *IAMLoginPolicyWriteModel { +func NewIAMLoginPolicyWriteModel() *IAMLoginPolicyWriteModel { return &IAMLoginPolicyWriteModel{ LoginPolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -42,7 +44,8 @@ func (wm *IAMLoginPolicyWriteModel) Reduce() error { func (wm *IAMLoginPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.LoginPolicyWriteModel.AggregateID) + AggregateIDs(wm.LoginPolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMLoginPolicyWriteModel) NewChangedEvent( diff --git a/internal/v2/command/iam_policy_org_iam.go b/internal/v2/command/iam_policy_org_iam.go index 56fa1528b9..8037d45e1e 100644 --- a/internal/v2/command/iam_policy_org_iam.go +++ b/internal/v2/command/iam_policy_org_iam.go @@ -9,8 +9,7 @@ import ( ) func (r *CommandSide) AddDefaultOrgIAMPolicy(ctx context.Context, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMOrgIAMPolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMOrgIAMPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel) err := r.addDefaultOrgIAMPolicy(ctx, nil, addedPolicy, policy) if err != nil { @@ -39,8 +38,7 @@ func (r *CommandSide) addDefaultOrgIAMPolicy(ctx context.Context, iamAgg *iam_re } func (r *CommandSide) ChangeDefaultOrgIAMPolicy(ctx context.Context, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) { - policy.AggregateID = r.iamID - existingPolicy, err := r.defaultOrgIAMPolicyWriteModelByID(ctx, policy.AggregateID) + existingPolicy, err := r.defaultOrgIAMPolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -65,7 +63,7 @@ func (r *CommandSide) ChangeDefaultOrgIAMPolicy(ctx context.Context, policy *dom } func (r *CommandSide) getDefaultOrgIAMPolicy(ctx context.Context) (*domain.OrgIAMPolicy, error) { - policyWriteModel, err := r.defaultOrgIAMPolicyWriteModelByID(ctx, r.iamID) + policyWriteModel, err := r.defaultOrgIAMPolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -74,11 +72,11 @@ func (r *CommandSide) getDefaultOrgIAMPolicy(ctx context.Context) (*domain.OrgIA return policy, nil } -func (r *CommandSide) defaultOrgIAMPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMOrgIAMPolicyWriteModel, err error) { +func (r *CommandSide) defaultOrgIAMPolicyWriteModelByID(ctx context.Context) (policy *IAMOrgIAMPolicyWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMOrgIAMPolicyWriteModel(iamID) + writeModel := NewIAMOrgIAMPolicyWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_policy_org_iam_model.go b/internal/v2/command/iam_policy_org_iam_model.go index 1113890fd8..c788900f5a 100644 --- a/internal/v2/command/iam_policy_org_iam_model.go +++ b/internal/v2/command/iam_policy_org_iam_model.go @@ -2,7 +2,9 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -10,11 +12,12 @@ type IAMOrgIAMPolicyWriteModel struct { PolicyOrgIAMWriteModel } -func NewIAMOrgIAMPolicyWriteModel(iamID string) *IAMOrgIAMPolicyWriteModel { +func NewIAMOrgIAMPolicyWriteModel() *IAMOrgIAMPolicyWriteModel { return &IAMOrgIAMPolicyWriteModel{ PolicyOrgIAMWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -37,7 +40,8 @@ func (wm *IAMOrgIAMPolicyWriteModel) Reduce() error { func (wm *IAMOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID) + AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*iam.OrgIAMPolicyChangedEvent, bool) { diff --git a/internal/v2/command/iam_policy_password_age.go b/internal/v2/command/iam_policy_password_age.go index f55757e63e..1e437b3f13 100644 --- a/internal/v2/command/iam_policy_password_age.go +++ b/internal/v2/command/iam_policy_password_age.go @@ -9,8 +9,7 @@ import ( ) func (r *CommandSide) AddDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMPasswordAgePolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMPasswordAgePolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel) err := r.addDefaultPasswordAgePolicy(ctx, nil, addedPolicy, policy) if err != nil { @@ -40,8 +39,7 @@ func (r *CommandSide) addDefaultPasswordAgePolicy(ctx context.Context, iamAgg *i } func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) { - policy.AggregateID = r.iamID - existingPolicy, err := r.defaultPasswordAgePolicyWriteModelByID(ctx, policy.AggregateID) + existingPolicy, err := r.defaultPasswordAgePolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -65,11 +63,11 @@ func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy return writeModelToPasswordAgePolicy(existingPolicy), nil } -func (r *CommandSide) defaultPasswordAgePolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordAgePolicyWriteModel, err error) { +func (r *CommandSide) defaultPasswordAgePolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordAgePolicyWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMPasswordAgePolicyWriteModel(iamID) + writeModel := NewIAMPasswordAgePolicyWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_policy_password_age_model.go b/internal/v2/command/iam_policy_password_age_model.go index 12418acaa2..9003bbcd20 100644 --- a/internal/v2/command/iam_policy_password_age_model.go +++ b/internal/v2/command/iam_policy_password_age_model.go @@ -2,7 +2,9 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -10,11 +12,12 @@ type IAMPasswordAgePolicyWriteModel struct { PasswordAgePolicyWriteModel } -func NewIAMPasswordAgePolicyWriteModel(iamID string) *IAMPasswordAgePolicyWriteModel { +func NewIAMPasswordAgePolicyWriteModel() *IAMPasswordAgePolicyWriteModel { return &IAMPasswordAgePolicyWriteModel{ PasswordAgePolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -37,7 +40,8 @@ func (wm *IAMPasswordAgePolicyWriteModel) Reduce() error { func (wm *IAMPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID) + AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*iam.PasswordAgePolicyChangedEvent, bool) { diff --git a/internal/v2/command/iam_policy_password_complexity.go b/internal/v2/command/iam_policy_password_complexity.go index 3cec1a171b..cf0fe62c9f 100644 --- a/internal/v2/command/iam_policy_password_complexity.go +++ b/internal/v2/command/iam_policy_password_complexity.go @@ -9,7 +9,7 @@ import ( ) func (r *CommandSide) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*domain.PasswordComplexityPolicy, error) { - policyWriteModel := NewIAMPasswordComplexityPolicyWriteModel(r.iamID) + policyWriteModel := NewIAMPasswordComplexityPolicyWriteModel() err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel) if err != nil { return nil, err @@ -20,8 +20,7 @@ func (r *CommandSide) GetDefaultPasswordComplexityPolicy(ctx context.Context) (* } func (r *CommandSide) AddDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMPasswordComplexityPolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMPasswordComplexityPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel) err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, addedPolicy, policy) if err != nil { @@ -55,12 +54,11 @@ func (r *CommandSide) addDefaultPasswordComplexityPolicy(ctx context.Context, ia } func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) { - policy.AggregateID = r.iamID if err := policy.IsValid(); err != nil { return nil, err } - existingPolicy, err := r.defaultPasswordComplexityPolicyWriteModelByID(ctx, policy.AggregateID) + existingPolicy, err := r.defaultPasswordComplexityPolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -83,11 +81,11 @@ func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, return writeModelToPasswordComplexityPolicy(existingPolicy), nil } -func (r *CommandSide) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordComplexityPolicyWriteModel, err error) { +func (r *CommandSide) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordComplexityPolicyWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMPasswordComplexityPolicyWriteModel(iamID) + writeModel := NewIAMPasswordComplexityPolicyWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_policy_password_complexity_model.go b/internal/v2/command/iam_policy_password_complexity_model.go index 6f67e89d43..70b6da595d 100644 --- a/internal/v2/command/iam_policy_password_complexity_model.go +++ b/internal/v2/command/iam_policy_password_complexity_model.go @@ -2,7 +2,9 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -10,11 +12,12 @@ type IAMPasswordComplexityPolicyWriteModel struct { PasswordComplexityPolicyWriteModel } -func NewIAMPasswordComplexityPolicyWriteModel(iamID string) *IAMPasswordComplexityPolicyWriteModel { +func NewIAMPasswordComplexityPolicyWriteModel() *IAMPasswordComplexityPolicyWriteModel { return &IAMPasswordComplexityPolicyWriteModel{ PasswordComplexityPolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -37,7 +40,8 @@ func (wm *IAMPasswordComplexityPolicyWriteModel) Reduce() error { func (wm *IAMPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID) + AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent( diff --git a/internal/v2/command/iam_policy_password_lockout.go b/internal/v2/command/iam_policy_password_lockout.go index bbe65ac442..06aa83ba13 100644 --- a/internal/v2/command/iam_policy_password_lockout.go +++ b/internal/v2/command/iam_policy_password_lockout.go @@ -9,8 +9,7 @@ import ( ) func (r *CommandSide) AddDefaultPasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) { - policy.AggregateID = r.iamID - addedPolicy := NewIAMPasswordLockoutPolicyWriteModel(policy.AggregateID) + addedPolicy := NewIAMPasswordLockoutPolicyWriteModel() iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel) err := r.addDefaultPasswordLockoutPolicy(ctx, nil, addedPolicy, policy) if err != nil { @@ -40,8 +39,7 @@ func (r *CommandSide) addDefaultPasswordLockoutPolicy(ctx context.Context, iamAg } func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) { - policy.AggregateID = r.iamID - existingPolicy, err := r.defaultPasswordLockoutPolicyWriteModelByID(ctx, policy.AggregateID) + existingPolicy, err := r.defaultPasswordLockoutPolicyWriteModelByID(ctx) if err != nil { return nil, err } @@ -65,11 +63,11 @@ func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, po return writeModelToPasswordLockoutPolicy(existingPolicy), nil } -func (r *CommandSide) defaultPasswordLockoutPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordLockoutPolicyWriteModel, err error) { +func (r *CommandSide) defaultPasswordLockoutPolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordLockoutPolicyWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel := NewIAMPasswordLockoutPolicyWriteModel(iamID) + writeModel := NewIAMPasswordLockoutPolicyWriteModel() err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/iam_policy_password_lockout_model.go b/internal/v2/command/iam_policy_password_lockout_model.go index f13a163988..70a7c7d062 100644 --- a/internal/v2/command/iam_policy_password_lockout_model.go +++ b/internal/v2/command/iam_policy_password_lockout_model.go @@ -2,7 +2,9 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/iam" ) @@ -10,11 +12,12 @@ type IAMPasswordLockoutPolicyWriteModel struct { PasswordLockoutPolicyWriteModel } -func NewIAMPasswordLockoutPolicyWriteModel(iamID string) *IAMPasswordLockoutPolicyWriteModel { +func NewIAMPasswordLockoutPolicyWriteModel() *IAMPasswordLockoutPolicyWriteModel { return &IAMPasswordLockoutPolicyWriteModel{ PasswordLockoutPolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: domain.IAMID, + ResourceOwner: domain.IAMID, }, }, } @@ -37,7 +40,8 @@ func (wm *IAMPasswordLockoutPolicyWriteModel) Reduce() error { func (wm *IAMPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType). - AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID) + AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*iam.PasswordLockoutPolicyChangedEvent, bool) { diff --git a/internal/v2/command/org.go b/internal/v2/command/org.go index 8334be1c2f..998a366a1e 100644 --- a/internal/v2/command/org.go +++ b/internal/v2/command/org.go @@ -32,7 +32,7 @@ func (r *CommandSide) setUpOrg(ctx context.Context, organisation *domain.Org, ad addedMember := NewOrgMemberWriteModel(orgAgg.ID(), userAgg.ID()) orgMemberAgg := OrgAggregateFromWriteModel(&addedMember.WriteModel) - err = r.addOrgMember(ctx, orgMemberAgg, addedMember, domain.NewMember(orgMemberAgg.ID(), userAgg.ID(), domain.OrgOwnerRole)) //TODO: correct? + err = r.addOrgMember(ctx, orgMemberAgg, addedMember, domain.NewMember(orgMemberAgg.ID(), userAgg.ID(), domain.RoleOrgOwner)) if err != nil { return nil, nil, nil, err } diff --git a/internal/v2/command/org_domain_model.go b/internal/v2/command/org_domain_model.go index 1f06471c4f..d35c45f7d7 100644 --- a/internal/v2/command/org_domain_model.go +++ b/internal/v2/command/org_domain_model.go @@ -22,7 +22,8 @@ type OrgDomainWriteModel struct { func NewOrgDomainWriteModel(orgID string, domain string) *OrgDomainWriteModel { return &OrgDomainWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: orgID, + AggregateID: orgID, + ResourceOwner: orgID, }, Domain: domain, } @@ -86,5 +87,6 @@ func (wm *OrgDomainWriteModel) Reduce() error { func (wm *OrgDomainWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/org_member_model.go b/internal/v2/command/org_member_model.go index 7549c6a57a..fd9075597f 100644 --- a/internal/v2/command/org_member_model.go +++ b/internal/v2/command/org_member_model.go @@ -13,7 +13,8 @@ func NewOrgMemberWriteModel(orgID, userID string) *OrgMemberWriteModel { return &OrgMemberWriteModel{ MemberWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: orgID, + AggregateID: orgID, + ResourceOwner: orgID, }, UserID: userID, }, @@ -48,5 +49,6 @@ func (wm *OrgMemberWriteModel) Reduce() error { func (wm *OrgMemberWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType). - AggregateIDs(wm.MemberWriteModel.AggregateID) + AggregateIDs(wm.MemberWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/org_model.go b/internal/v2/command/org_model.go index 5c6cc52846..eaa93e37ec 100644 --- a/internal/v2/command/org_model.go +++ b/internal/v2/command/org_model.go @@ -17,7 +17,8 @@ type OrgWriteModel struct { func NewOrgWriteModel(orgID string) *OrgWriteModel { return &OrgWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: orgID, + AggregateID: orgID, + ResourceOwner: orgID, }, } } @@ -48,7 +49,8 @@ func (wm *OrgWriteModel) Reduce() error { func (wm *OrgWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func OrgAggregateFromWriteModel(wm *eventstore.WriteModel) *org.Aggregate { diff --git a/internal/v2/command/org_policy_org_iam_model.go b/internal/v2/command/org_policy_org_iam_model.go index 9a8a69da4c..f1dea71aa9 100644 --- a/internal/v2/command/org_policy_org_iam_model.go +++ b/internal/v2/command/org_policy_org_iam_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/repository/org" ) @@ -14,7 +15,8 @@ func NewORGOrgIAMPolicyWriteModel(orgID string) *ORGOrgIAMPolicyWriteModel { return &ORGOrgIAMPolicyWriteModel{ PolicyOrgIAMWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: orgID, + AggregateID: orgID, + ResourceOwner: orgID, }, }, } @@ -37,7 +39,8 @@ func (wm *ORGOrgIAMPolicyWriteModel) Reduce() error { func (wm *ORGOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType). - AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID) + AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*org.OrgIAMPolicyChangedEvent, bool) { diff --git a/internal/v2/command/org_policy_password_complexity_model.go b/internal/v2/command/org_policy_password_complexity_model.go index cb5e141673..337767febc 100644 --- a/internal/v2/command/org_policy_password_complexity_model.go +++ b/internal/v2/command/org_policy_password_complexity_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/repository/org" ) @@ -10,11 +11,12 @@ type OrgPasswordComplexityPolicyWriteModel struct { PasswordComplexityPolicyWriteModel } -func NewOrgPasswordComplexityPolicyWriteModel(iamID string) *OrgPasswordComplexityPolicyWriteModel { +func NewOrgPasswordComplexityPolicyWriteModel(orgID string) *OrgPasswordComplexityPolicyWriteModel { return &OrgPasswordComplexityPolicyWriteModel{ PasswordComplexityPolicyWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: iamID, + AggregateID: orgID, + ResourceOwner: orgID, }, }, } @@ -37,7 +39,8 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) Reduce() error { func (wm *OrgPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType). - AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID) + AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent( diff --git a/internal/v2/command/project.go b/internal/v2/command/project.go new file mode 100644 index 0000000000..bcc8b25b6c --- /dev/null +++ b/internal/v2/command/project.go @@ -0,0 +1,65 @@ +package command + +import ( + "context" + + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +func (r *CommandSide) AddProject(ctx context.Context, project *domain.Project, resourceOwner, ownerUserID string) (_ *domain.Project, err error) { + projectAgg, addedProject, err := r.addProject(ctx, project, resourceOwner, ownerUserID) + if err != nil { + return nil, err + } + err = r.eventstore.PushAggregate(ctx, addedProject, projectAgg) + if err != nil { + return nil, err + } + + return projectWriteModelToProject(addedProject), nil +} + +func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID string) (_ *project.Aggregate, _ *ProjectWriteModel, err error) { + if !projectAdd.IsValid() { + return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") + } + projectAdd.AggregateID, err = r.idGenerator.Next() + if err != nil { + return nil, nil, err + } +// TODO: Add uniqueness check + addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner) + projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel) + + projectRole := domain.RoleOrgOwner + //if global { //TODO: ! + // projectRole = domain.RoleProjectOwnerGlobal + //} + projectAgg.PushEvents( + project.NewProjectAddedEvent(ctx, projectAdd.Name), + project.NewMemberAddedEvent(ctx, ownerUserID, projectRole), + ) + return projectAgg, addedProject, nil +} + +func (r *CommandSide) getProjectByID(ctx context.Context, projectID, resourceOwner string) (*domain.Project, error) { + projectWriteModel, err := r.getProjectWriteModelByID(ctx, projectID, resourceOwner) + if err != nil { + return nil, err + } + if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved { + return nil, caos_errs.ThrowNotFound(nil, "PROJECT-Gd2hh", "Errors.Project.NotFound") + } + return projectWriteModelToProject(projectWriteModel), nil +} + +func (r *CommandSide) getProjectWriteModelByID(ctx context.Context, projectID, resourceOwner string) (*ProjectWriteModel, error) { + projectWriteModel := NewProjectWriteModel(projectID, resourceOwner) + err := r.eventstore.FilterToQueryReducer(ctx, projectWriteModel) + if err != nil { + return nil, err + } + return projectWriteModel, nil +} diff --git a/internal/v2/command/project_application.go b/internal/v2/command/project_application.go new file mode 100644 index 0000000000..8f6aa56241 --- /dev/null +++ b/internal/v2/command/project_application.go @@ -0,0 +1,73 @@ +package command + +import ( + "context" + + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +func (r *CommandSide) AddApplication(ctx context.Context, application *domain.Application, resourceOwner string) (_ *domain.Application, err error) { + project, err := r.getProjectByID(ctx, application.AggregateID, resourceOwner) + if err != nil { + return nil, err + } + addedApplication := NewApplicationWriteModel(application.AggregateID, resourceOwner) + projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel) + err = r.addApplication(ctx, projectAgg, project, application) + if err != nil { + return nil, err + } + err = r.eventstore.PushAggregate(ctx, addedApplication, projectAgg) + if err != nil { + return nil, err + } + + return applicationWriteModelToApplication(addedApplication), nil +} + +func (r *CommandSide) addApplication(ctx context.Context, projectAgg *project.Aggregate, proj *domain.Project, application *domain.Application) (err error) { + if !application.IsValid(true) { + return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid") + } + application.AppID, err = r.idGenerator.Next() + if err != nil { + return err + } + + projectAgg.PushEvents(project.NewApplicationAddedEvent(ctx, application.AppID, application.Name, application.Type)) + + var stringPw string + if application.OIDCConfig != nil { + application.OIDCConfig.AppID = application.AppID + err = application.OIDCConfig.GenerateNewClientID(r.idGenerator, proj) + if err != nil { + return err + } + stringPw, err = application.OIDCConfig.GenerateClientSecretIfNeeded(r.applicationSecretGenerator) + if err != nil { + return err + } + projectAgg.PushEvents(project.NewOIDCConfigAddedEvent(ctx, + application.OIDCConfig.OIDCVersion, + application.OIDCConfig.AppID, + application.OIDCConfig.ClientID, + application.OIDCConfig.ClientSecret, + application.OIDCConfig.RedirectUris, + application.OIDCConfig.ResponseTypes, + application.OIDCConfig.GrantTypes, + application.OIDCConfig.ApplicationType, + application.OIDCConfig.AuthMethodType, + application.OIDCConfig.PostLogoutRedirectUris, + application.OIDCConfig.DevMode, + application.OIDCConfig.AccessTokenType, + application.OIDCConfig.AccessTokenRoleAssertion, + application.OIDCConfig.IDTokenRoleAssertion, + application.OIDCConfig.IDTokenUserinfoAssertion, + application.OIDCConfig.ClockSkew)) + } + _ = stringPw + + return nil +} diff --git a/internal/v2/command/project_application_model.go b/internal/v2/command/project_application_model.go new file mode 100644 index 0000000000..8a9a18b47b --- /dev/null +++ b/internal/v2/command/project_application_model.go @@ -0,0 +1,55 @@ +package command + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +type ApplicationWriteModel struct { + eventstore.WriteModel + + AppID string + State domain.AppState + Name string + Type domain.AppType + OIDCConfig *domain.OIDCConfig +} + +func NewApplicationWriteModel(projectID, resourceOwner string) *ApplicationWriteModel { + return &ApplicationWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + } +} + +func (wm *ApplicationWriteModel) AppendEvents(events ...eventstore.EventReader) { + wm.WriteModel.AppendEvents(events...) + for _, event := range events { + switch e := event.(type) { + case *project.ApplicationAddedEvent: + wm.WriteModel.AppendEvents(e) + } + } +} + +func (wm *ApplicationWriteModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *project.ApplicationAddedEvent: + wm.Name = e.Name + wm.State = domain.AppStateActive + //case *project.ApplicationChangedEvent: + // wm.Name = e.Name + } + } + return nil +} + +func (wm *ApplicationWriteModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType). + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) +} diff --git a/internal/v2/command/project_converter.go b/internal/v2/command/project_converter.go new file mode 100644 index 0000000000..2502955dfc --- /dev/null +++ b/internal/v2/command/project_converter.go @@ -0,0 +1,25 @@ +package command + +import ( + "github.com/caos/zitadel/internal/v2/domain" +) + +func projectWriteModelToProject(writeModel *ProjectWriteModel) *domain.Project { + return &domain.Project{ + ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel), + Name: writeModel.Name, + ProjectRoleAssertion: writeModel.ProjectRoleAssertion, + ProjectRoleCheck: writeModel.ProjectRoleCheck, + } +} + +func applicationWriteModelToApplication(writeModel *ApplicationWriteModel) *domain.Application { + return &domain.Application{ + ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel), + AppID: writeModel.AggregateID, + State: writeModel.State, + Name: writeModel.Name, + Type: writeModel.Type, + //TODO: OIDC Config + } +} diff --git a/internal/v2/command/project_member.go b/internal/v2/command/project_member.go new file mode 100644 index 0000000000..a61cae1a0a --- /dev/null +++ b/internal/v2/command/project_member.go @@ -0,0 +1,112 @@ +package command + +import ( + "context" + "reflect" + + "github.com/caos/zitadel/internal/errors" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/telemetry/tracing" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +func (r *CommandSide) AddProjectMember(ctx context.Context, member *domain.Member, resourceOwner string) (*domain.Member, error) { + addedMember := NewProjectMemberWriteModel(member.AggregateID, member.UserID, resourceOwner) + projectAgg := ProjectAggregateFromWriteModel(&addedMember.WriteModel) + err := r.addProjectMember(ctx, projectAgg, addedMember, member) + if err != nil { + return nil, err + } + + err = r.eventstore.PushAggregate(ctx, addedMember, projectAgg) + if err != nil { + return nil, err + } + + return memberWriteModelToMember(&addedMember.MemberWriteModel), nil +} + +func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *project.Aggregate, addedMember *ProjectMemberWriteModel, member *domain.Member) error { + //TODO: check if roles valid + + if !member.IsValid() { + return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-W8m4l", "Errors.Project.MemberInvalid") + } + + err := r.eventstore.FilterToQueryReducer(ctx, addedMember) + if err != nil { + return err + } + if addedMember.State == domain.MemberStateActive { + return errors.ThrowAlreadyExists(nil, "PROJECT-PtXi1", "Errors.Project.Member.AlreadyExists") + } + + projectAgg.PushEvents(project.NewMemberAddedEvent(ctx, member.UserID, member.Roles...)) + + return nil +} + +//ChangeProjectMember updates an existing member +func (r *CommandSide) ChangeProjectMember(ctx context.Context, member *domain.Member, resourceOwner string) (*domain.Member, error) { + //TODO: check if roles valid + + if !member.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.MemberInvalid") + } + + existingMember, err := r.projectMemberWriteModelByID(ctx, member.AggregateID, member.UserID, resourceOwner) + if err != nil { + return nil, err + } + + if reflect.DeepEqual(existingMember.Roles, member.Roles) { + return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.Member.RolesNotChanged") + } + projectAgg := ProjectAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel) + projectAgg.PushEvents(project.NewMemberChangedEvent(ctx, member.UserID, member.Roles...)) + + events, err := r.eventstore.PushAggregates(ctx, projectAgg) + if err != nil { + return nil, err + } + + existingMember.AppendEvents(events...) + if err = existingMember.Reduce(); err != nil { + return nil, err + } + + return memberWriteModelToMember(&existingMember.MemberWriteModel), nil +} + +func (r *CommandSide) RemoveProjectMember(ctx context.Context, projectID, userID, resourceOwner string) error { + m, err := r.projectMemberWriteModelByID(ctx, projectID, userID, resourceOwner) + if err != nil && !errors.IsNotFound(err) { + return err + } + if errors.IsNotFound(err) { + return nil + } + + projectAgg := ProjectAggregateFromWriteModel(&m.MemberWriteModel.WriteModel) + projectAgg.PushEvents(project.NewMemberRemovedEvent(ctx, userID)) + + return r.eventstore.PushAggregate(ctx, m, projectAgg) +} + +func (r *CommandSide) projectMemberWriteModelByID(ctx context.Context, projectID, userID, resourceOwner string) (member *ProjectMemberWriteModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + writeModel := NewProjectMemberWriteModel(projectID, userID, resourceOwner) + err = r.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + + if writeModel.State == domain.MemberStateUnspecified || writeModel.State == domain.MemberStateRemoved { + return nil, errors.ThrowNotFound(nil, "PROJECT-D8JxR", "Errors.NotFound") + } + + return writeModel, nil +} diff --git a/internal/v2/command/project_member_model.go b/internal/v2/command/project_member_model.go new file mode 100644 index 0000000000..d17e8f62ea --- /dev/null +++ b/internal/v2/command/project_member_model.go @@ -0,0 +1,54 @@ +package command + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +type ProjectMemberWriteModel struct { + MemberWriteModel +} + +func NewProjectMemberWriteModel(projectID, userID, resourceOwner string) *ProjectMemberWriteModel { + return &ProjectMemberWriteModel{ + MemberWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + UserID: userID, + }, + } +} + +func (wm *ProjectMemberWriteModel) AppendEvents(events ...eventstore.EventReader) { + for _, event := range events { + switch e := event.(type) { + case *project.MemberAddedEvent: + if e.UserID != wm.MemberWriteModel.UserID { + continue + } + wm.MemberWriteModel.AppendEvents(&e.MemberAddedEvent) + case *project.MemberChangedEvent: + if e.UserID != wm.MemberWriteModel.UserID { + continue + } + wm.MemberWriteModel.AppendEvents(&e.MemberChangedEvent) + case *project.MemberRemovedEvent: + if e.UserID != wm.MemberWriteModel.UserID { + continue + } + wm.MemberWriteModel.AppendEvents(&e.MemberRemovedEvent) + } + } +} + +func (wm *ProjectMemberWriteModel) Reduce() error { + return wm.MemberWriteModel.Reduce() +} + +func (wm *ProjectMemberWriteModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType). + AggregateIDs(wm.MemberWriteModel.AggregateID). + ResourceOwner(wm.ResourceOwner) +} diff --git a/internal/v2/command/project_model.go b/internal/v2/command/project_model.go new file mode 100644 index 0000000000..67e4232665 --- /dev/null +++ b/internal/v2/command/project_model.go @@ -0,0 +1,60 @@ +package command + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +type ProjectWriteModel struct { + eventstore.WriteModel + + Name string + ProjectRoleAssertion bool + ProjectRoleCheck bool + State domain.ProjectState +} + +func NewProjectWriteModel(projectID string, resourceOwner string) *ProjectWriteModel { + return &ProjectWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + } +} + +func (wm *ProjectWriteModel) AppendEvents(events ...eventstore.EventReader) { + wm.WriteModel.AppendEvents(events...) + for _, event := range events { + switch e := event.(type) { + case *project.ProjectAddedEvent: + wm.WriteModel.AppendEvents(e) + } + } +} + +func (wm *ProjectWriteModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *project.ProjectAddedEvent: + wm.Name = e.Name + wm.State = domain.ProjectStateActive + //case *project.ProjectChangedEvent: + // wm.Name = e.Name + } + } + return nil +} + +func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType). + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) +} + +func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *project.Aggregate { + return &project.Aggregate{ + Aggregate: *eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion), + } +} diff --git a/internal/v2/command/setup.go b/internal/v2/command/setup.go index 625caef30c..ab95b82fbe 100644 --- a/internal/v2/command/setup.go +++ b/internal/v2/command/setup.go @@ -22,7 +22,7 @@ const ( ) func (r *CommandSide) ExecuteSetupSteps(ctx context.Context, steps []Step) error { - iam, err := r.GetIAM(ctx, r.iamID) + iam, err := r.GetIAM(ctx) if err != nil && !caos_errs.IsNotFound(err) { return err } @@ -32,13 +32,13 @@ func (r *CommandSide) ExecuteSetupSteps(ctx context.Context, steps []Step) error } if iam == nil { - iam = &domain.IAM{ObjectRoot: models.ObjectRoot{AggregateID: r.iamID}} + iam = &domain.IAM{ObjectRoot: models.ObjectRoot{}} } - ctx = setSetUpContextData(ctx, r.iamID) + ctx = setSetUpContextData(ctx) for _, step := range steps { - iam, err = r.StartSetup(ctx, r.iamID, step.Step()) + iam, err = r.StartSetup(ctx, step.Step()) if err != nil { return err } @@ -51,12 +51,12 @@ func (r *CommandSide) ExecuteSetupSteps(ctx context.Context, steps []Step) error return nil } -func setSetUpContextData(ctx context.Context, orgID string) context.Context { - return authz.SetCtxData(ctx, authz.CtxData{UserID: SetupUser, OrgID: orgID}) +func setSetUpContextData(ctx context.Context) context.Context { + return authz.SetCtxData(ctx, authz.CtxData{UserID: SetupUser}) } -func (r *CommandSide) StartSetup(ctx context.Context, iamID string, step domain.Step) (*domain.IAM, error) { - iamWriteModel, err := r.iamByID(ctx, iamID) +func (r *CommandSide) StartSetup(ctx context.Context, step domain.Step) (*domain.IAM, error) { + iamWriteModel, err := r.getIAMWriteModel(ctx) if err != nil && !caos_errs.IsNotFound(err) { return nil, err } @@ -68,11 +68,12 @@ func (r *CommandSide) StartSetup(ctx context.Context, iamID string, step domain. if err != nil { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Grgh1", "Setup start failed") } + logging.LogWithFields("SETUP-fhh21", "step", step).Info("setup step started") return writeModelToIAM(iamWriteModel), nil } func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider func(*IAMWriteModel) (*iam_repo.Aggregate, error)) error { - iam, err := r.iamByID(ctx, r.iamID) + iam, err := r.getIAMWriteModel(ctx) if err != nil && !caos_errs.IsNotFound(err) { return err } @@ -89,44 +90,6 @@ func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider if err != nil { return caos_errs.ThrowPreconditionFailedf(nil, "EVENT-dbG31", "Setup %s failed", step.Step()) } + logging.LogWithFields("SETUP-Sg1t1", "step", step.Step()).Info("setup step done") return nil } - -//func (r *CommandSide) setupDone(ctx context.Context, iamAgg *iam_repo.Aggregate, event eventstore.EventPusher, aggregates ...eventstore.Aggregater) error { -// aggregate := iamAgg.PushEvents(event) -// -// aggregates = append(aggregates, aggregate) -// _, err := r.eventstore.PushAggregates(ctx, aggregates...) -// if err != nil { -// return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dgd2", "Setup done failed") -// } -// return nil -//} - -// -////TODO: should not use readmodel -//func (r *CommandSide) setup(ctx context.Context, iamID string, step iam_repo.Step, event eventstore.EventPusher) (*iam_model.IAM, error) { -// iam, err := r.iamByID(ctx, iamID) -// if err != nil && !caos_errs.IsNotFound(err) { -// return nil, err -// } -// -// if iam != nil && (iam.SetUpStarted >= iam_repo.Step(step) || iam.SetUpStarted != iam.SetUpDone) { -// return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error") -// } -// -// aggregate := query.AggregateFromReadModel(iam). -// PushEvents(event) -// -// events, err := r.eventstore.PushAggregates(ctx, aggregate) -// if err != nil { -// return nil, err -// } -// -// if err = iam.AppendAndReduce(events...); err != nil { -// return nil, err -// } -// return nil, nil -// //TODO: return write model -// //return readModelToIAM(iam), nil -//} diff --git a/internal/v2/command/setup_step1.go b/internal/v2/command/setup_step1.go index 2a3a070437..fe88cb9990 100644 --- a/internal/v2/command/setup_step1.go +++ b/internal/v2/command/setup_step1.go @@ -3,24 +3,36 @@ package command import ( "context" + "github.com/caos/logging" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +const ( + OIDCResponseTypeCode = "CODE" + OIDCResponseTypeIDToken = "ID_TOKEN" + OIDCResponseTypeToken = "ID_TOKEN TOKEN" + OIDCGrantTypeAuthorizationCode = "AUTHORIZATION_CODE" + OIDCGrantTypeImplicit = "IMPLICIT" + OIDCGrantTypeRefreshToken = "REFRESH_TOKEN" + OIDCApplicationTypeNative = "NATIVE" + OIDCApplicationTypeUserAgent = "USER_AGENT" + OIDCApplicationTypeWeb = "WEB" + OIDCAuthMethodTypeNone = "NONE" + OIDCAuthMethodTypeBasic = "BASIC" + OIDCAuthMethodTypePost = "POST" ) type Step1 struct { GlobalOrg string IAMProject string - DefaultLoginPolicy LoginPolicy //*iam_model.LoginPolicy + DefaultLoginPolicy LoginPolicy Orgs []Org - Owners []string - - //setup *Setup - //createdUsers map[string]*usr_model.User - //createdOrgs map[string]*org_model.Org - //createdProjects map[string]*proj_model.Project - //pwComplexityPolicy *iam_model.PasswordComplexityPolicyView } func (s *Step1) Step() domain.Step { @@ -28,7 +40,7 @@ func (s *Step1) Step() domain.Step { } func (s *Step1) execute(ctx context.Context, commandSide *CommandSide) error { - return commandSide.SetupStep1(ctx, commandSide.iamID, s) + return commandSide.SetupStep1(ctx, s) } type LoginPolicy struct { @@ -71,10 +83,11 @@ type OIDCApp struct { DevMode bool } -func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 *Step1) error { - iamAgg := iam_repo.NewAggregate(r.iamID, "", 0) +func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error { + iamWriteModel := NewIAMWriteModel() + iamAgg := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel) //create default login policy - err := r.addDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(iamAgg.ID()), + err := r.addDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(), &domain.LoginPolicy{ AllowUsernamePassword: step1.DefaultLoginPolicy.AllowUsernamePassword, AllowRegister: step1.DefaultLoginPolicy.AllowRegister, @@ -83,6 +96,7 @@ func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 *Step1 if err != nil { return err } + logging.Log("SETUP-sd2hj").Info("default login policy set up") //create orgs aggregates := make([]eventstore.Aggregater, 0) for _, organisation := range step1.Orgs { @@ -110,6 +124,8 @@ func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 *Step1 if err != nil { return err } + logging.LogWithFields("SETUP-Gdsfg", "id", orgAgg.ID(), "name", organisation.Name).Info("org set up") + if organisation.OrgIamPolicy { err = r.addOrgIAMPolicy(ctx, orgAgg, NewORGOrgIAMPolicyWriteModel(orgAgg.ID()), &domain.OrgIAMPolicy{UserLoginMustBeDomain: false}) if err != nil { @@ -117,24 +133,43 @@ func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 *Step1 } } aggregates = append(aggregates, orgAgg, userAgg, orgMemberAgg) + if organisation.Name == step1.GlobalOrg { + err = r.setGlobalOrg(ctx, iamAgg, iamWriteModel, orgAgg.ID()) + if err != nil { + return err + } + logging.Log("SETUP-BDn52").Info("global org set") + } //projects - //create applications + for _, proj := range organisation.Projects { + project := &domain.Project{Name: proj.Name} + projectAgg, _, err := r.addProject(ctx, project, orgAgg.ID(), userAgg.ID()) + if err != nil { + return err + } + if project.Name == step1.IAMProject { + err = r.setIAMProject(ctx, iamAgg, iamWriteModel, projectAgg.ID()) + if err != nil { + return err + } + logging.Log("SETUP-Bdfs1").Info("IAM project set") + err = r.addIAMMember(ctx, iamAgg, NewIAMMemberWriteModel(userAgg.ID()), domain.NewMember(iamAgg.ID(), userAgg.ID(), domain.RoleIAMOwner)) + if err != nil { + return err + } + logging.Log("SETUP-BSf2h").Info("IAM owner set") + } + //create applications + for _, app := range proj.OIDCApps { + err = setUpApplication(ctx, r, projectAgg, project, app) + if err != nil { + return err + } + } + aggregates = append(aggregates, projectAgg) + } } - //set iam owners - //set global org - //set iam project id - - /*aggregates: - iam: - default login policy - iam owner - org: - default - caos - zitadel - - */ iamAgg.PushEvents(iam_repo.NewSetupStepDoneEvent(ctx, domain.Step1)) _, err = r.eventstore.PushAggregates(ctx, append(aggregates, iamAgg)...) @@ -143,3 +178,91 @@ func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 *Step1 } return nil } + +func setUpApplication(ctx context.Context, r *CommandSide, projectAgg *project.Aggregate, project *domain.Project, oidcApp OIDCApp) error { + app := &domain.Application{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projectAgg.ID(), + }, + Name: oidcApp.Name, + Type: domain.AppTypeOIDC, + OIDCConfig: &domain.OIDCConfig{ + RedirectUris: oidcApp.RedirectUris, + ResponseTypes: getOIDCResponseTypes(oidcApp.ResponseTypes), + GrantTypes: getOIDCGrantTypes(oidcApp.GrantTypes), + ApplicationType: getOIDCApplicationType(oidcApp.ApplicationType), + AuthMethodType: getOIDCAuthMethod(oidcApp.AuthMethodType), + DevMode: oidcApp.DevMode, + }, + } + err := r.addApplication(ctx, projectAgg, project, app) + if err != nil { + return err + } + logging.LogWithFields("SETUP-Edgw4", "name", app.Name, "clientID", app.OIDCConfig.ClientID).Info("application set up") + return nil +} + +func getOIDCResponseTypes(responseTypes []string) []domain.OIDCResponseType { + types := make([]domain.OIDCResponseType, len(responseTypes)) + for i, t := range responseTypes { + types[i] = getOIDCResponseType(t) + } + return types +} + +func getOIDCResponseType(responseType string) domain.OIDCResponseType { + switch responseType { + case OIDCResponseTypeCode: + return domain.OIDCResponseTypeCode + case OIDCResponseTypeIDToken: + return domain.OIDCResponseTypeIDToken + case OIDCResponseTypeToken: + return domain.OIDCResponseTypeIDTokenToken + } + return domain.OIDCResponseTypeCode +} + +func getOIDCGrantTypes(grantTypes []string) []domain.OIDCGrantType { + types := make([]domain.OIDCGrantType, len(grantTypes)) + for i, t := range grantTypes { + types[i] = getOIDCGrantType(t) + } + return types +} + +func getOIDCGrantType(grantTypes string) domain.OIDCGrantType { + switch grantTypes { + case OIDCGrantTypeAuthorizationCode: + return domain.OIDCGrantTypeAuthorizationCode + case OIDCGrantTypeImplicit: + return domain.OIDCGrantTypeImplicit + case OIDCGrantTypeRefreshToken: + return domain.OIDCGrantTypeRefreshToken + } + return domain.OIDCGrantTypeAuthorizationCode +} + +func getOIDCApplicationType(appType string) domain.OIDCApplicationType { + switch appType { + case OIDCApplicationTypeNative: + return domain.OIDCApplicationTypeNative + case OIDCApplicationTypeUserAgent: + return domain.OIDCApplicationTypeUserAgent + case OIDCApplicationTypeWeb: + return domain.OIDCApplicationTypeWeb + } + return domain.OIDCApplicationTypeWeb +} + +func getOIDCAuthMethod(authMethod string) domain.OIDCAuthMethodType { + switch authMethod { + case OIDCAuthMethodTypeNone: + return domain.OIDCAuthMethodTypeNone + case OIDCAuthMethodTypeBasic: + return domain.OIDCAuthMethodTypeBasic + case OIDCAuthMethodTypePost: + return domain.OIDCAuthMethodTypePost + } + return domain.OIDCAuthMethodTypeBasic +} diff --git a/internal/v2/command/setup_step2.go b/internal/v2/command/setup_step2.go index aea175b6c9..039cf750c4 100644 --- a/internal/v2/command/setup_step2.go +++ b/internal/v2/command/setup_step2.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -23,7 +25,7 @@ func (s *Step2) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep2(ctx context.Context, step *Step2) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) - err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, NewIAMPasswordComplexityPolicyWriteModel(iam.AggregateID), &domain.PasswordComplexityPolicy{ + err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, NewIAMPasswordComplexityPolicyWriteModel(), &domain.PasswordComplexityPolicy{ MinLength: step.DefaultPasswordComplexityPolicy.MinLength, HasLowercase: step.DefaultPasswordComplexityPolicy.HasLowercase, HasUppercase: step.DefaultPasswordComplexityPolicy.HasUppercase, @@ -33,7 +35,8 @@ func (r *CommandSide) SetupStep2(ctx context.Context, step *Step2) error { if err != nil { return nil, err } - return iamAgg, err + logging.Log("SETUP-ADgd2").Info("default password complexity policy set up") + return iamAgg, nil } return r.setup(ctx, step, fn) } diff --git a/internal/v2/command/setup_step3.go b/internal/v2/command/setup_step3.go index 5707175af8..c1e3b3f8a0 100644 --- a/internal/v2/command/setup_step3.go +++ b/internal/v2/command/setup_step3.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -23,13 +25,14 @@ func (s *Step3) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep3(ctx context.Context, step *Step3) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) - err := r.addDefaultPasswordAgePolicy(ctx, iamAgg, NewIAMPasswordAgePolicyWriteModel(iam.AggregateID), &domain.PasswordAgePolicy{ + err := r.addDefaultPasswordAgePolicy(ctx, iamAgg, NewIAMPasswordAgePolicyWriteModel(), &domain.PasswordAgePolicy{ MaxAgeDays: step.DefaultPasswordAgePolicy.MaxAgeDays, ExpireWarnDays: step.DefaultPasswordAgePolicy.ExpireWarnDays, }) if err != nil { return nil, err } + logging.Log("SETUP-DBqgq").Info("default password age policy set up") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step4.go b/internal/v2/command/setup_step4.go index dba404cd87..c1502c67ec 100644 --- a/internal/v2/command/setup_step4.go +++ b/internal/v2/command/setup_step4.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -23,13 +25,14 @@ func (s *Step4) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep4(ctx context.Context, step *Step4) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) - err := r.addDefaultPasswordLockoutPolicy(ctx, iamAgg, NewIAMPasswordLockoutPolicyWriteModel(iam.AggregateID), &domain.PasswordLockoutPolicy{ + err := r.addDefaultPasswordLockoutPolicy(ctx, iamAgg, NewIAMPasswordLockoutPolicyWriteModel(), &domain.PasswordLockoutPolicy{ MaxAttempts: step.DefaultPasswordLockoutPolicy.MaxAttempts, ShowLockOutFailures: step.DefaultPasswordLockoutPolicy.ShowLockOutFailures, }) if err != nil { return nil, err } + logging.Log("SETUP-Bfnge").Info("default password lockout policy set up") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step5.go b/internal/v2/command/setup_step5.go index 0f647b8e67..69c4b6733f 100644 --- a/internal/v2/command/setup_step5.go +++ b/internal/v2/command/setup_step5.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -23,12 +25,13 @@ func (s *Step5) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep5(ctx context.Context, step *Step5) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) - err := r.addDefaultOrgIAMPolicy(ctx, iamAgg, NewIAMOrgIAMPolicyWriteModel(iam.AggregateID), &domain.OrgIAMPolicy{ + err := r.addDefaultOrgIAMPolicy(ctx, iamAgg, NewIAMOrgIAMPolicyWriteModel(), &domain.OrgIAMPolicy{ UserLoginMustBeDomain: step.DefaultOrgIAMPolicy.UserLoginMustBeDomain, }) if err != nil { return nil, err } + logging.Log("SETUP-ADgd2").Info("default org iam policy set up") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step6.go b/internal/v2/command/setup_step6.go index 282906a716..6bde7db1a6 100644 --- a/internal/v2/command/setup_step6.go +++ b/internal/v2/command/setup_step6.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -23,13 +25,14 @@ func (s *Step6) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep6(ctx context.Context, step *Step6) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) - err := r.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(iam.AggregateID), &domain.LabelPolicy{ + err := r.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(), &domain.LabelPolicy{ PrimaryColor: step.DefaultLabelPolicy.PrimaryColor, SecondaryColor: step.DefaultLabelPolicy.SecondaryColor, }) if err != nil { return nil, err } + logging.Log("SETUP-ADgd2").Info("default label policy set up") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step7.go b/internal/v2/command/setup_step7.go index 977c74efcc..0a80283d5d 100644 --- a/internal/v2/command/setup_step7.go +++ b/internal/v2/command/setup_step7.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -22,7 +24,7 @@ func (s *Step7) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep7(ctx context.Context, step *Step7) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { - secondFactorModel := NewIAMSecondFactorWriteModel(iam.AggregateID) + secondFactorModel := NewIAMSecondFactorWriteModel() iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel) if !step.OTP { return iamAgg, nil @@ -31,6 +33,7 @@ func (r *CommandSide) SetupStep7(ctx context.Context, step *Step7) error { if err != nil { return nil, err } + logging.Log("SETUP-Dggsg").Info("added OTP to 2FA login policy") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step8.go b/internal/v2/command/setup_step8.go index aa1fa4f99a..14a53446d6 100644 --- a/internal/v2/command/setup_step8.go +++ b/internal/v2/command/setup_step8.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -22,7 +24,7 @@ func (s *Step8) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep8(ctx context.Context, step *Step8) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { - secondFactorModel := NewIAMSecondFactorWriteModel(iam.AggregateID) + secondFactorModel := NewIAMSecondFactorWriteModel() iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel) if !step.U2F { return iamAgg, nil @@ -31,6 +33,7 @@ func (r *CommandSide) SetupStep8(ctx context.Context, step *Step8) error { if err != nil { return nil, err } + logging.Log("SETUP-BDhne").Info("added U2F to 2FA login policy") return iamAgg, nil } return r.setup(ctx, step, fn) diff --git a/internal/v2/command/setup_step9.go b/internal/v2/command/setup_step9.go index f8a445b4c6..f563611d77 100644 --- a/internal/v2/command/setup_step9.go +++ b/internal/v2/command/setup_step9.go @@ -3,6 +3,8 @@ package command import ( "context" + "github.com/caos/logging" + iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" @@ -22,7 +24,7 @@ func (s *Step9) execute(ctx context.Context, commandSide *CommandSide) error { func (r *CommandSide) SetupStep9(ctx context.Context, step *Step9) error { fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { - multiFactorModel := NewIAMMultiFactorWriteModel(iam.AggregateID) + multiFactorModel := NewIAMMultiFactorWriteModel() iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel) if !step.Passwordless { return iamAgg, nil @@ -31,10 +33,12 @@ func (r *CommandSide) SetupStep9(ctx context.Context, step *Step9) error { if err != nil { return nil, err } + logging.Log("SETUP-AEG2t").Info("allowed passwordless in login policy") err = r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, iam_model.MultiFactorTypeU2FWithPIN) if err != nil { return nil, err } + logging.Log("SETUP-ADfng").Info("added passwordless to MFA login policy") return iamAgg, err } return r.setup(ctx, step, fn) @@ -46,5 +50,5 @@ func setPasswordlessAllowedInPolicy(ctx context.Context, c *CommandSide, iamAgg return err } policy.PasswordlessType = domain.PasswordlessTypeAllowed - return c.changeDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(iamAgg.ID()), policy) + return c.changeDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(), policy) } diff --git a/internal/v2/command/user.go b/internal/v2/command/user.go index c52b9b4197..7d490adbbf 100644 --- a/internal/v2/command/user.go +++ b/internal/v2/command/user.go @@ -2,6 +2,7 @@ package command import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/v2/domain" @@ -48,7 +49,7 @@ func (r *CommandSide) ChangeUsername(ctx context.Context, orgID, userID, userNam if orgID == "" || userID == "" || userName == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2N9fs", "Errors.IDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, orgID) if err != nil { return err } @@ -74,11 +75,11 @@ func (r *CommandSide) ChangeUsername(ctx context.Context, orgID, userID, userNam return r.eventstore.PushAggregate(ctx, existingUser, userAgg) } -func (r *CommandSide) DeactivateUser(ctx context.Context, userID string) (*domain.User, error) { +func (r *CommandSide) DeactivateUser(ctx context.Context, userID, resourceOwner string) (*domain.User, error) { if userID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-m0gDf", "Errors.User.UserIDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -98,11 +99,11 @@ func (r *CommandSide) DeactivateUser(ctx context.Context, userID string) (*domai return writeModelToUser(existingUser), nil } -func (r *CommandSide) ReactivateUser(ctx context.Context, userID string) (*domain.User, error) { +func (r *CommandSide) ReactivateUser(ctx context.Context, userID, resourceOwner string) (*domain.User, error) { if userID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9ds", "Errors.User.UserIDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -122,11 +123,11 @@ func (r *CommandSide) ReactivateUser(ctx context.Context, userID string) (*domai return writeModelToUser(existingUser), nil } -func (r *CommandSide) LockUser(ctx context.Context, userID string) (*domain.User, error) { +func (r *CommandSide) LockUser(ctx context.Context, userID, resourceOwner string) (*domain.User, error) { if userID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0sd", "Errors.User.UserIDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -146,11 +147,11 @@ func (r *CommandSide) LockUser(ctx context.Context, userID string) (*domain.User return writeModelToUser(existingUser), nil } -func (r *CommandSide) UnlockUser(ctx context.Context, userID string) (*domain.User, error) { +func (r *CommandSide) UnlockUser(ctx context.Context, userID, resourceOwner string) (*domain.User, error) { if userID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-M0dse", "Errors.User.UserIDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -170,11 +171,11 @@ func (r *CommandSide) UnlockUser(ctx context.Context, userID string) (*domain.Us return writeModelToUser(existingUser), nil } -func (r *CommandSide) RemoveUser(ctx context.Context, userID string) error { +func (r *CommandSide) RemoveUser(ctx context.Context, userID, resourceOwner string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing") } - existingUser, err := r.userWriteModelByID(ctx, userID) + existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return err } @@ -189,11 +190,11 @@ func (r *CommandSide) RemoveUser(ctx context.Context, userID string) error { return r.eventstore.PushAggregate(ctx, existingUser, userAgg) } -func (r *CommandSide) userWriteModelByID(ctx context.Context, userID string) (writeModel *UserWriteModel, err error) { +func (r *CommandSide) userWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *UserWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewUserWriteModel(userID) + writeModel = NewUserWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human.go b/internal/v2/command/user_human.go index 7ad30b7aac..ef7b79980c 100644 --- a/internal/v2/command/user_human.go +++ b/internal/v2/command/user_human.go @@ -39,7 +39,7 @@ func (r *CommandSide) addHuman(ctx context.Context, orgID, username string, huma return nil, nil, err } - addedHuman := NewHumanWriteModel(human.AggregateID) + addedHuman := NewHumanWriteModel(human.AggregateID, orgID) //TODO: Check Unique Username if err := human.CheckOrgIAMPolicy(username, orgIAMPolicy); err != nil { return nil, nil, err @@ -118,7 +118,7 @@ func (r *CommandSide) RegisterHuman(ctx context.Context, orgID, username string, return nil, err } - addedHuman := NewHumanWriteModel(human.AggregateID) + addedHuman := NewHumanWriteModel(human.AggregateID, orgID) //TODO: Check Unique Username or unique external idp if err := human.CheckOrgIAMPolicy(username, orgIAMPolicy); err != nil { return nil, err @@ -185,12 +185,12 @@ func (r *CommandSide) RegisterHuman(ctx context.Context, orgID, username string, return writeModelToHuman(addedHuman), nil } -func (r *CommandSide) ResendInitialMail(ctx context.Context, userID, email string) (err error) { +func (r *CommandSide) ResendInitialMail(ctx context.Context, userID, email, resourceOwner string) (err error) { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.UserIDMissing") } - existingEmail, err := r.emailWriteModel(ctx, userID) + existingEmail, err := r.emailWriteModel(ctx, userID, resourceOwner) if err != nil { return err } diff --git a/internal/v2/command/user_human_address.go b/internal/v2/command/user_human_address.go index d0da894481..beeb6f330b 100644 --- a/internal/v2/command/user_human_address.go +++ b/internal/v2/command/user_human_address.go @@ -8,7 +8,7 @@ import ( ) func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *domain.Address) (*domain.Address, error) { - existingAddress, err := r.addressWriteModel(ctx, address.AggregateID) + existingAddress, err := r.addressWriteModel(ctx, address.AggregateID, address.ResourceOwner) if err != nil { return nil, err } @@ -30,11 +30,11 @@ func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *domain.Ad return writeModelToAddress(existingAddress), nil } -func (r *CommandSide) addressWriteModel(ctx context.Context, userID string) (writeModel *HumanAddressWriteModel, err error) { +func (r *CommandSide) addressWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *HumanAddressWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanAddressWriteModel(userID) + writeModel = NewHumanAddressWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_address_model.go b/internal/v2/command/user_human_address_model.go index 7515af587f..19c4b8f3d6 100644 --- a/internal/v2/command/user_human_address_model.go +++ b/internal/v2/command/user_human_address_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" @@ -19,10 +20,11 @@ type HumanAddressWriteModel struct { State domain.AddressState } -func NewHumanAddressWriteModel(userID string) *HumanAddressWriteModel { +func NewHumanAddressWriteModel(userID, resourceOwner string) *HumanAddressWriteModel { return &HumanAddressWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -82,7 +84,8 @@ func (wm *HumanAddressWriteModel) Reduce() error { func (wm *HumanAddressWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *HumanAddressWriteModel) NewChangedEvent( diff --git a/internal/v2/command/user_human_email.go b/internal/v2/command/user_human_email.go index e47b97568b..4ba02bde28 100644 --- a/internal/v2/command/user_human_email.go +++ b/internal/v2/command/user_human_email.go @@ -13,7 +13,7 @@ func (r *CommandSide) ChangeHumanEmail(ctx context.Context, email *domain.Email) return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9sf", "Errors.Email.Invalid") } - existingEmail, err := r.emailWriteModel(ctx, email.AggregateID) + existingEmail, err := r.emailWriteModel(ctx, email.AggregateID, email.ResourceOwner) if err != nil { return nil, err } @@ -45,12 +45,12 @@ func (r *CommandSide) ChangeHumanEmail(ctx context.Context, email *domain.Email) return writeModelToEmail(existingEmail), nil } -func (r *CommandSide) CreateHumanEmailVerificationCode(ctx context.Context, userID string) error { +func (r *CommandSide) CreateHumanEmailVerificationCode(ctx context.Context, userID, resourceOwner string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing") } - existingEmail, err := r.emailWriteModel(ctx, userID) + existingEmail, err := r.emailWriteModel(ctx, userID, resourceOwner) if err != nil { return err } @@ -73,11 +73,11 @@ func (r *CommandSide) CreateHumanEmailVerificationCode(ctx context.Context, user return r.eventstore.PushAggregate(ctx, existingEmail, userAgg) } -func (r *CommandSide) emailWriteModel(ctx context.Context, userID string) (writeModel *HumanEmailWriteModel, err error) { +func (r *CommandSide) emailWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *HumanEmailWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanEmailWriteModel(userID) + writeModel = NewHumanEmailWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_email_model.go b/internal/v2/command/user_human_email_model.go index 917b9805cd..2c33c3c52b 100644 --- a/internal/v2/command/user_human_email_model.go +++ b/internal/v2/command/user_human_email_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" @@ -16,10 +17,11 @@ type HumanEmailWriteModel struct { UserState domain.UserState } -func NewHumanEmailWriteModel(userID string) *HumanEmailWriteModel { +func NewHumanEmailWriteModel(userID, resourceOwner string) *HumanEmailWriteModel { return &HumanEmailWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -65,7 +67,8 @@ func (wm *HumanEmailWriteModel) Reduce() error { func (wm *HumanEmailWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *HumanEmailWriteModel) NewChangedEvent( diff --git a/internal/v2/command/user_human_externalidp.go b/internal/v2/command/user_human_externalidp.go index 663659e804..e3be4e1c0d 100644 --- a/internal/v2/command/user_human_externalidp.go +++ b/internal/v2/command/user_human_externalidp.go @@ -17,7 +17,7 @@ func (r *CommandSide) removeHumanExternalIDP(ctx context.Context, externalIDP *d return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3M9ds", "Errors.IDMissing") } - existingExternalIDP, err := r.externalIDPWriteModelByID(ctx, externalIDP.AggregateID, externalIDP.IDPConfigID, externalIDP.ExternalUserID) + existingExternalIDP, err := r.externalIDPWriteModelByID(ctx, externalIDP.AggregateID, externalIDP.IDPConfigID, externalIDP.ExternalUserID, externalIDP.ResourceOwner) if err != nil { return err } @@ -39,11 +39,11 @@ func (r *CommandSide) removeHumanExternalIDP(ctx context.Context, externalIDP *d return r.eventstore.PushAggregate(ctx, existingExternalIDP, userAgg) } -func (r *CommandSide) externalIDPWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID string) (writeModel *HumanExternalIDPWriteModel, err error) { +func (r *CommandSide) externalIDPWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID, resourceOwner string) (writeModel *HumanExternalIDPWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID) + writeModel = NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_externalidp_model.go b/internal/v2/command/user_human_externalidp_model.go index e5a116be95..43f842535e 100644 --- a/internal/v2/command/user_human_externalidp_model.go +++ b/internal/v2/command/user_human_externalidp_model.go @@ -16,10 +16,11 @@ type HumanExternalIDPWriteModel struct { State domain.ExternalIDPState } -func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID string) *HumanExternalIDPWriteModel { +func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner string) *HumanExternalIDPWriteModel { return &HumanExternalIDPWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, IDPConfigID: idpConfigID, ExternalUserID: externalUserID, @@ -68,5 +69,6 @@ func (wm *HumanExternalIDPWriteModel) Reduce() error { func (wm *HumanExternalIDPWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/user_human_model.go b/internal/v2/command/user_human_model.go index 053232b638..acfed20f8f 100644 --- a/internal/v2/command/user_human_model.go +++ b/internal/v2/command/user_human_model.go @@ -38,10 +38,11 @@ type HumanWriteModel struct { UserState domain.UserState } -func NewHumanWriteModel(userID string) *HumanWriteModel { +func NewHumanWriteModel(userID, resourceOwner string) *HumanWriteModel { return &HumanWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -115,7 +116,8 @@ func (wm *HumanWriteModel) Reduce() error { func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *HumanWriteModel) reduceHumanAddedEvent(e *user.HumanAddedEvent) { diff --git a/internal/v2/command/user_human_otp.go b/internal/v2/command/user_human_otp.go index 484611f2a7..65b4ff36d2 100644 --- a/internal/v2/command/user_human_otp.go +++ b/internal/v2/command/user_human_otp.go @@ -8,12 +8,12 @@ import ( "github.com/caos/zitadel/internal/v2/repository/user" ) -func (r *CommandSide) RemoveHumanOTP(ctx context.Context, userID string) error { +func (r *CommandSide) RemoveHumanOTP(ctx context.Context, userID, resourceOwner string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0sd", "Errors.User.UserIDMissing") } - existingOTP, err := r.otpWriteModelByID(ctx, userID) + existingOTP, err := r.otpWriteModelByID(ctx, userID, resourceOwner) if err != nil { return err } @@ -28,11 +28,11 @@ func (r *CommandSide) RemoveHumanOTP(ctx context.Context, userID string) error { return r.eventstore.PushAggregate(ctx, existingOTP, userAgg) } -func (r *CommandSide) otpWriteModelByID(ctx context.Context, userID string) (writeModel *HumanOTPWriteModel, err error) { +func (r *CommandSide) otpWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanOTPWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanOTPWriteModel(userID) + writeModel = NewHumanOTPWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_otp_model.go b/internal/v2/command/user_human_otp_model.go index c010218acf..07b13d284f 100644 --- a/internal/v2/command/user_human_otp_model.go +++ b/internal/v2/command/user_human_otp_model.go @@ -15,10 +15,11 @@ type HumanOTPWriteModel struct { State domain.OTPState } -func NewHumanOTPWriteModel(userID string) *HumanOTPWriteModel { +func NewHumanOTPWriteModel(userID, resourceOwner string) *HumanOTPWriteModel { return &HumanOTPWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -53,5 +54,6 @@ func (wm *HumanOTPWriteModel) Reduce() error { func (wm *HumanOTPWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/user_human_password.go b/internal/v2/command/user_human_password.go index d98177db97..f2eca34f75 100644 --- a/internal/v2/command/user_human_password.go +++ b/internal/v2/command/user_human_password.go @@ -13,7 +13,7 @@ func (r *CommandSide) SetOneTimePassword(ctx context.Context, orgID, userID, pas ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - existingPassword, err := r.passwordWriteModel(ctx, userID) + existingPassword, err := r.passwordWriteModel(ctx, userID, orgID) if err != nil { return err } @@ -24,11 +24,11 @@ func (r *CommandSide) SetOneTimePassword(ctx context.Context, orgID, userID, pas return r.changePassword(ctx, orgID, userID, "", password, existingPassword) } -func (r *CommandSide) ChangePassword(ctx context.Context, orgID, userID, oldPassword, newPassword, userAgentID string) (err error) { +func (r *CommandSide) ChangePassword(ctx context.Context, orgID, userID, oldPassword, newPassword, userAgentID, resourceOwner string) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - existingPassword, err := r.passwordWriteModel(ctx, userID) + existingPassword, err := r.passwordWriteModel(ctx, userID, resourceOwner) if err != nil { return err } @@ -74,8 +74,8 @@ func (r *CommandSide) changePassword(ctx context.Context, orgID, userID, userAge return r.eventstore.PushAggregate(ctx, existingPassword, userAgg) } -func (r *CommandSide) RequestSetPassword(ctx context.Context, userID string, notifyType domain.NotificationType) (err error) { - existingHuman, err := r.userWriteModelByID(ctx, userID) +func (r *CommandSide) RequestSetPassword(ctx context.Context, userID, resourceOwner string, notifyType domain.NotificationType) (err error) { + existingHuman, err := r.userWriteModelByID(ctx, userID, resourceOwner) if err != nil { return err } @@ -94,11 +94,11 @@ func (r *CommandSide) RequestSetPassword(ctx context.Context, userID string, not return r.eventstore.PushAggregate(ctx, existingHuman, userAgg) } -func (r *CommandSide) passwordWriteModel(ctx context.Context, userID string) (writeModel *HumanPasswordWriteModel, err error) { +func (r *CommandSide) passwordWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *HumanPasswordWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanPasswordWriteModel(userID) + writeModel = NewHumanPasswordWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_password_model.go b/internal/v2/command/user_human_password_model.go index a61a0c2c0e..f3ca35be50 100644 --- a/internal/v2/command/user_human_password_model.go +++ b/internal/v2/command/user_human_password_model.go @@ -16,10 +16,11 @@ type HumanPasswordWriteModel struct { UserState domain.UserState } -func NewHumanPasswordWriteModel(userID string) *HumanPasswordWriteModel { +func NewHumanPasswordWriteModel(userID, resourceOwner string) *HumanPasswordWriteModel { return &HumanPasswordWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -66,5 +67,6 @@ func (wm *HumanPasswordWriteModel) Reduce() error { func (wm *HumanPasswordWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/user_human_phone.go b/internal/v2/command/user_human_phone.go index e4355ed40c..320c6174d3 100644 --- a/internal/v2/command/user_human_phone.go +++ b/internal/v2/command/user_human_phone.go @@ -2,6 +2,7 @@ package command import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/v2/domain" @@ -13,7 +14,7 @@ func (r *CommandSide) ChangeHumanPhone(ctx context.Context, phone *domain.Phone) return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0ds", "Errors.Phone.Invalid") } - existingPhone, err := r.phoneWriteModel(ctx, phone.AggregateID) + existingPhone, err := r.phoneWriteModel(ctx, phone.AggregateID, phone.ResourceOwner) if err != nil { return nil, err } @@ -45,12 +46,12 @@ func (r *CommandSide) ChangeHumanPhone(ctx context.Context, phone *domain.Phone) return writeModelToPhone(existingPhone), nil } -func (r *CommandSide) CreateHumanPhoneVerificationCode(ctx context.Context, userID string) error { +func (r *CommandSide) CreateHumanPhoneVerificationCode(ctx context.Context, userID, resourceOwner string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing") } - existingPhone, err := r.phoneWriteModel(ctx, userID) + existingPhone, err := r.phoneWriteModel(ctx, userID, resourceOwner) if err != nil { return err } @@ -69,12 +70,12 @@ func (r *CommandSide) CreateHumanPhoneVerificationCode(ctx context.Context, user return r.eventstore.PushAggregate(ctx, existingPhone, userAgg) } -func (r *CommandSide) RemoveHumanPhone(ctx context.Context, userID string) error { +func (r *CommandSide) RemoveHumanPhone(ctx context.Context, userID, resourceOwner string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0ds", "Errors.User.UserIDMissing") } - existingPhone, err := r.phoneWriteModel(ctx, userID) + existingPhone, err := r.phoneWriteModel(ctx, userID, resourceOwner) if err != nil { return err } @@ -88,11 +89,11 @@ func (r *CommandSide) RemoveHumanPhone(ctx context.Context, userID string) error return r.eventstore.PushAggregate(ctx, existingPhone, userAgg) } -func (r *CommandSide) phoneWriteModel(ctx context.Context, userID string) (writeModel *HumanPhoneWriteModel, err error) { +func (r *CommandSide) phoneWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *HumanPhoneWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanPhoneWriteModel(userID) + writeModel = NewHumanPhoneWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_phone_model.go b/internal/v2/command/user_human_phone_model.go index 34ad3fe6af..d5ac27a227 100644 --- a/internal/v2/command/user_human_phone_model.go +++ b/internal/v2/command/user_human_phone_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" @@ -16,10 +17,11 @@ type HumanPhoneWriteModel struct { State domain.PhoneState } -func NewHumanPhoneWriteModel(userID string) *HumanPhoneWriteModel { +func NewHumanPhoneWriteModel(userID, resourceOwner string) *HumanPhoneWriteModel { return &HumanPhoneWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -71,7 +73,8 @@ func (wm *HumanPhoneWriteModel) Reduce() error { func (wm *HumanPhoneWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *HumanPhoneWriteModel) NewChangedEvent( diff --git a/internal/v2/command/user_human_profile.go b/internal/v2/command/user_human_profile.go index 445aeb512e..282dd87b13 100644 --- a/internal/v2/command/user_human_profile.go +++ b/internal/v2/command/user_human_profile.go @@ -12,7 +12,7 @@ func (r *CommandSide) ChangeHumanProfile(ctx context.Context, profile *domain.Pr return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8io0d", "Errors.User.Profile.Invalid") } - existingProfile, err := r.profileWriteModelByID(ctx, profile.AggregateID) + existingProfile, err := r.profileWriteModelByID(ctx, profile.AggregateID, profile.ResourceOwner) if err != nil { return nil, err } @@ -34,11 +34,11 @@ func (r *CommandSide) ChangeHumanProfile(ctx context.Context, profile *domain.Pr return writeModelToProfile(existingProfile), nil } -func (r *CommandSide) profileWriteModelByID(ctx context.Context, userID string) (writeModel *HumanProfileWriteModel, err error) { +func (r *CommandSide) profileWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanProfileWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanProfileWriteModel(userID) + writeModel = NewHumanProfileWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_profile_model.go b/internal/v2/command/user_human_profile_model.go index db50e43407..0acfcd74ea 100644 --- a/internal/v2/command/user_human_profile_model.go +++ b/internal/v2/command/user_human_profile_model.go @@ -2,10 +2,12 @@ package command import ( "context" + + "golang.org/x/text/language" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" - "golang.org/x/text/language" ) type HumanProfileWriteModel struct { @@ -21,10 +23,11 @@ type HumanProfileWriteModel struct { UserState domain.UserState } -func NewHumanProfileWriteModel(userID string) *HumanProfileWriteModel { +func NewHumanProfileWriteModel(userID, resourceOwner string) *HumanProfileWriteModel { return &HumanProfileWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -89,7 +92,8 @@ func (wm *HumanProfileWriteModel) Reduce() error { func (wm *HumanProfileWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *HumanProfileWriteModel) NewChangedEvent( diff --git a/internal/v2/command/user_human_webauthn.go b/internal/v2/command/user_human_webauthn.go index ade816778b..bd28e167db 100644 --- a/internal/v2/command/user_human_webauthn.go +++ b/internal/v2/command/user_human_webauthn.go @@ -9,22 +9,22 @@ import ( "github.com/caos/zitadel/internal/v2/repository/user" ) -func (r *CommandSide) RemoveHumanU2F(ctx context.Context, userID, webAuthNID string) error { +func (r *CommandSide) RemoveHumanU2F(ctx context.Context, userID, webAuthNID, resourceOwner string) error { event := user.NewHumanU2FRemovedEvent(ctx, webAuthNID) - return r.removeHumanWebAuthN(ctx, userID, webAuthNID, event) + return r.removeHumanWebAuthN(ctx, userID, webAuthNID, resourceOwner, event) } -func (r *CommandSide) RemoveHumanPasswordless(ctx context.Context, userID, webAuthNID string) error { +func (r *CommandSide) RemoveHumanPasswordless(ctx context.Context, userID, webAuthNID, resourceOwner string) error { event := user.NewHumanPasswordlessRemovedEvent(ctx, webAuthNID) - return r.removeHumanWebAuthN(ctx, userID, webAuthNID, event) + return r.removeHumanWebAuthN(ctx, userID, webAuthNID, resourceOwner, event) } -func (r *CommandSide) removeHumanWebAuthN(ctx context.Context, userID, webAuthNID string, event eventstore.EventPusher) error { +func (r *CommandSide) removeHumanWebAuthN(ctx context.Context, userID, webAuthNID, resourceOwner string, event eventstore.EventPusher) error { if userID == "" || webAuthNID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M9de", "Errors.IDMissing") } - existingWebAuthN, err := r.webauthNWriteModelByID(ctx, userID, webAuthNID) + existingWebAuthN, err := r.webauthNWriteModelByID(ctx, userID, webAuthNID, resourceOwner) if err != nil { return err } @@ -37,11 +37,11 @@ func (r *CommandSide) removeHumanWebAuthN(ctx context.Context, userID, webAuthNI return r.eventstore.PushAggregate(ctx, existingWebAuthN, userAgg) } -func (r *CommandSide) webauthNWriteModelByID(ctx context.Context, userID, webAuthNID string) (writeModel *HumanWebAuthNWriteModel, err error) { +func (r *CommandSide) webauthNWriteModelByID(ctx context.Context, userID, webAuthNID, resourceOwner string) (writeModel *HumanWebAuthNWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewHumanWebAuthNWriteModel(userID, webAuthNID) + writeModel = NewHumanWebAuthNWriteModel(userID, webAuthNID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_human_webauthn_model.go b/internal/v2/command/user_human_webauthn_model.go index 968cb7795b..26a2adc247 100644 --- a/internal/v2/command/user_human_webauthn_model.go +++ b/internal/v2/command/user_human_webauthn_model.go @@ -14,10 +14,11 @@ type HumanWebAuthNWriteModel struct { State domain.WebAuthNState } -func NewHumanWebAuthNWriteModel(userID, wbAuthNTokenID string) *HumanWebAuthNWriteModel { +func NewHumanWebAuthNWriteModel(userID, wbAuthNTokenID, resourceOwner string) *HumanWebAuthNWriteModel { return &HumanWebAuthNWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, WebauthNTokenID: wbAuthNTokenID, } @@ -57,5 +58,6 @@ func (wm *HumanWebAuthNWriteModel) Reduce() error { func (wm *HumanWebAuthNWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } diff --git a/internal/v2/command/user_machine.go b/internal/v2/command/user_machine.go index 4952e083b0..d206b39536 100644 --- a/internal/v2/command/user_machine.go +++ b/internal/v2/command/user_machine.go @@ -26,7 +26,7 @@ func (r *CommandSide) AddMachine(ctx context.Context, orgID, username string, ma return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6M0ds", "Errors.User.Invalid") } - addedMachine := NewMachineWriteModel(machine.AggregateID) + addedMachine := NewMachineWriteModel(machine.AggregateID, orgID) userAgg := UserAggregateFromWriteModel(&addedMachine.WriteModel) userAgg.PushEvents( user.NewMachineAddedEvent( @@ -40,7 +40,7 @@ func (r *CommandSide) AddMachine(ctx context.Context, orgID, username string, ma } func (r *CommandSide) ChangeMachine(ctx context.Context, machine *domain.Machine) (*domain.Machine, error) { - existingUser, err := r.machineWriteModelByID(ctx, machine.AggregateID) + existingUser, err := r.machineWriteModelByID(ctx, machine.AggregateID, machine.ResourceOwner) if err != nil { return nil, err } @@ -62,14 +62,14 @@ func (r *CommandSide) ChangeMachine(ctx context.Context, machine *domain.Machine return writeModelToMachine(existingUser), nil } -func (r *CommandSide) machineWriteModelByID(ctx context.Context, userID string) (writeModel *MachineWriteModel, err error) { +func (r *CommandSide) machineWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *MachineWriteModel, err error) { if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5M0ds", "Errors.User.UserIDMissing") } ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - writeModel = NewMachineWriteModel(userID) + writeModel = NewMachineWriteModel(userID, resourceOwner) err = r.eventstore.FilterToQueryReducer(ctx, writeModel) if err != nil { return nil, err diff --git a/internal/v2/command/user_machine_model.go b/internal/v2/command/user_machine_model.go index fa947d90c7..4e4ca3e3e9 100644 --- a/internal/v2/command/user_machine_model.go +++ b/internal/v2/command/user_machine_model.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" @@ -17,10 +18,11 @@ type MachineWriteModel struct { UserState domain.UserState } -func NewMachineWriteModel(userID string) *MachineWriteModel { +func NewMachineWriteModel(userID, resourceOwner string) *MachineWriteModel { return &MachineWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -91,7 +93,8 @@ func (wm *MachineWriteModel) Reduce() error { func (wm *MachineWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func (wm *MachineWriteModel) NewChangedEvent( diff --git a/internal/v2/command/user_model.go b/internal/v2/command/user_model.go index 2326644700..b8b2f4d80a 100644 --- a/internal/v2/command/user_model.go +++ b/internal/v2/command/user_model.go @@ -1,11 +1,12 @@ package command import ( + "strings" + caos_errors "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/user" - "strings" ) type UserWriteModel struct { @@ -15,10 +16,11 @@ type UserWriteModel struct { UserState domain.UserState } -func NewUserWriteModel(userID string) *UserWriteModel { +func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel { return &UserWriteModel{ WriteModel: eventstore.WriteModel{ - AggregateID: userID, + AggregateID: userID, + ResourceOwner: resourceOwner, }, } } @@ -86,7 +88,8 @@ func (wm *UserWriteModel) Reduce() error { func (wm *UserWriteModel) Query() *eventstore.SearchQueryBuilder { return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). - AggregateIDs(wm.AggregateID) + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner) } func UserAggregateFromWriteModel(wm *eventstore.WriteModel) *user.Aggregate { diff --git a/internal/v2/domain/application.go b/internal/v2/domain/application.go new file mode 100644 index 0000000000..a543ab3e13 --- /dev/null +++ b/internal/v2/domain/application.go @@ -0,0 +1,49 @@ +package domain + +import ( + "github.com/caos/zitadel/internal/eventstore/models" +) + +type Application struct { + models.ObjectRoot + + AppID string + State AppState + Name string + Type AppType + OIDCConfig *OIDCConfig +} + +type AppState int32 + +const ( + AppStateUnspecified AppState = iota + AppStateActive + AppStateInactive + AppStateRemoved +) + +type AppType int32 + +const ( + AppTypeUnspecified AppType = iota + AppTypeOIDC + AppTypeSAML +) + +func NewApplication(projectID, appID string) *Application { + return &Application{ObjectRoot: models.ObjectRoot{AggregateID: projectID}, AppID: appID, State: AppStateActive} +} + +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 + } + return true +} diff --git a/internal/v2/domain/iam.go b/internal/v2/domain/iam.go index 3f522ffa8b..fbb7f49101 100644 --- a/internal/v2/domain/iam.go +++ b/internal/v2/domain/iam.go @@ -4,6 +4,10 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" ) +const ( + IAMID = "IAM" +) + type IAM struct { models.ObjectRoot diff --git a/internal/v2/domain/oidc_config.go b/internal/v2/domain/oidc_config.go new file mode 100644 index 0000000000..41673937cb --- /dev/null +++ b/internal/v2/domain/oidc_config.go @@ -0,0 +1,152 @@ +package domain + +import ( + "fmt" + "strings" + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/id" +) + +type OIDCConfig struct { + models.ObjectRoot + + AppID string + ClientID string + ClientSecret *crypto.CryptoValue + ClientSecretString string + RedirectUris []string + ResponseTypes []OIDCResponseType + GrantTypes []OIDCGrantType + ApplicationType OIDCApplicationType + AuthMethodType OIDCAuthMethodType + PostLogoutRedirectUris []string + OIDCVersion OIDCVersion + Compliance *Compliance + DevMode bool + AccessTokenType OIDCTokenType + AccessTokenRoleAssertion bool + IDTokenRoleAssertion bool + IDTokenUserinfoAssertion bool + ClockSkew time.Duration +} + +type OIDCVersion int32 + +const ( + OIDCVersionV1 OIDCVersion = iota +) + +type OIDCResponseType int32 + +const ( + OIDCResponseTypeCode OIDCResponseType = iota + OIDCResponseTypeIDToken + OIDCResponseTypeIDTokenToken +) + +type OIDCGrantType int32 + +const ( + OIDCGrantTypeAuthorizationCode OIDCGrantType = iota + OIDCGrantTypeImplicit + OIDCGrantTypeRefreshToken +) + +type OIDCApplicationType int32 + +const ( + OIDCApplicationTypeWeb OIDCApplicationType = iota + OIDCApplicationTypeUserAgent + OIDCApplicationTypeNative +) + +type OIDCAuthMethodType int32 + +const ( + OIDCAuthMethodTypeBasic OIDCAuthMethodType = iota + OIDCAuthMethodTypePost + OIDCAuthMethodTypeNone +) + +type Compliance struct { + NoneCompliant bool + Problems []string +} + +type OIDCTokenType int32 + +const ( + OIDCTokenTypeBearer OIDCTokenType = iota + OIDCTokenTypeJWT +) + +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 == OIDCAuthMethodTypeNone { + return "", nil + } + return c.GenerateNewClientSecret(generator) +} + +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 "", errors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret") + } + c.ClientSecret = cryptoValue + return stringSecret, 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/v2/domain/project.go b/internal/v2/domain/project.go new file mode 100644 index 0000000000..8b9ce65cc3 --- /dev/null +++ b/internal/v2/domain/project.go @@ -0,0 +1,31 @@ +package domain + +import ( + "github.com/caos/zitadel/internal/eventstore/models" +) + +type Project struct { + models.ObjectRoot + + State ProjectState + Name string + Members []*Member + Roles []*ProjectRole + //Applications []*Application + //Grants []*ProjectGrant + ProjectRoleAssertion bool + ProjectRoleCheck bool +} + +type ProjectState int32 + +const ( + ProjectStateUnspecified ProjectState = iota + ProjectStateActive + ProjectStateInactive + ProjectStateRemoved +) + +func (o *Project) IsValid() bool { + return o.Name != "" +} diff --git a/internal/v2/domain/project_role.go b/internal/v2/domain/project_role.go new file mode 100644 index 0000000000..afcb1fc798 --- /dev/null +++ b/internal/v2/domain/project_role.go @@ -0,0 +1,21 @@ +package domain + +import ( + "github.com/caos/zitadel/internal/eventstore/models" +) + +type ProjectRole struct { + models.ObjectRoot + + Key string + DisplayName string + Group string +} + +func NewProjectRole(projectID, key string) *ProjectRole { + return &ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: projectID}, Key: key} +} + +func (p *ProjectRole) IsValid() bool { + return p.AggregateID != "" && p.Key != "" +} diff --git a/internal/v2/domain/roles.go b/internal/v2/domain/roles.go index 1b3dfb7d54..1c1fa189dc 100644 --- a/internal/v2/domain/roles.go +++ b/internal/v2/domain/roles.go @@ -1,5 +1,8 @@ package domain const ( - OrgOwnerRole = "ORG_OWNER" + RoleOrgOwner = "ORG_OWNER" + RoleIAMOwner = "IAM_OWNER" + RoleProjectOwner = "PROJECT_OWNER" + RoleProjectOwnerGlobal = "PROJECT_OWNER_GLOBAL" ) diff --git a/internal/v2/repository/iam/event_iam_project_set.go b/internal/v2/repository/iam/event_iam_project_set.go index 2d2b37758f..a0e353abdc 100644 --- a/internal/v2/repository/iam/event_iam_project_set.go +++ b/internal/v2/repository/iam/event_iam_project_set.go @@ -23,7 +23,7 @@ func (e *ProjectSetEvent) Data() interface{} { return e } -func NewProjectSetEvent(ctx context.Context, projectID string) *ProjectSetEvent { +func NewIAMProjectSetEvent(ctx context.Context, projectID string) *ProjectSetEvent { return &ProjectSetEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, diff --git a/internal/v2/repository/project/aggregate.go b/internal/v2/repository/project/aggregate.go new file mode 100644 index 0000000000..6847dd92ed --- /dev/null +++ b/internal/v2/repository/project/aggregate.go @@ -0,0 +1,31 @@ +package project + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" +) + +const ( + AggregateType = "project" + AggregateVersion = "v1" +) + +type Aggregate struct { + eventstore.Aggregate +} + +func NewAggregate( + id, + resourceOwner string, + previousSequence uint64, +) *Aggregate { + + return &Aggregate{ + Aggregate: *eventstore.NewAggregate( + id, + AggregateType, + resourceOwner, + AggregateVersion, + previousSequence, + ), + } +} diff --git a/internal/v2/repository/project/application.go b/internal/v2/repository/project/application.go new file mode 100644 index 0000000000..978cc093c9 --- /dev/null +++ b/internal/v2/repository/project/application.go @@ -0,0 +1,57 @@ +package project + +import ( + "context" + "encoding/json" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" + "github.com/caos/zitadel/internal/v2/domain" +) + +const ( + applicationEventTypePrefix = projectEventTypePrefix + "application." + ApplicationAdded = applicationEventTypePrefix + "added" + ApplicationChanged = applicationEventTypePrefix + "changed" + ApplicationDeactivated = applicationEventTypePrefix + "deactivated" + ApplicationReactivated = applicationEventTypePrefix + "reactivated" + ApplicationRemoved = applicationEventTypePrefix + "removed" +) + +type ApplicationAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId,omitempty"` + Name string `json:"name,omitempty"` + AppType domain.AppType `json:"appType,omitempty"` +} + +func (e *ApplicationAddedEvent) Data() interface{} { + return e +} + +func NewApplicationAddedEvent(ctx context.Context, appID, name string, appType domain.AppType) *ApplicationAddedEvent { + return &ApplicationAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + ApplicationAdded, + ), + AppID: appID, + Name: name, + AppType: appType, + } +} + +func ApplicationAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ApplicationAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "APPLICATION-Nffg2", "unable to unmarshal application") + } + + return e, nil +} diff --git a/internal/v2/repository/project/member.go b/internal/v2/repository/project/member.go new file mode 100644 index 0000000000..ef63ea58b8 --- /dev/null +++ b/internal/v2/repository/project/member.go @@ -0,0 +1,76 @@ +package project + +import ( + "context" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/member" +) + +var ( + MemberAddedEventType = projectEventTypePrefix + member.AddedEventType + MemberChangedEventType = projectEventTypePrefix + member.ChangedEventType + MemberRemovedEventType = projectEventTypePrefix + member.RemovedEventType +) + +type MemberAddedEvent struct { + member.MemberAddedEvent +} + +func NewMemberAddedEvent( + ctx context.Context, + userID string, + roles ...string, +) *MemberAddedEvent { + return &MemberAddedEvent{ + MemberAddedEvent: *member.NewMemberAddedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberAddedEventType, + ), + userID, + roles..., + ), + } +} + +type MemberChangedEvent struct { + member.MemberChangedEvent +} + +func NewMemberChangedEvent( + ctx context.Context, + userID string, + roles ...string, +) *MemberChangedEvent { + + return &MemberChangedEvent{ + MemberChangedEvent: *member.NewMemberChangedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberChangedEventType, + ), + userID, + roles..., + ), + } +} + +type MemberRemovedEvent struct { + member.MemberRemovedEvent +} + +func NewMemberRemovedEvent( + ctx context.Context, + userID string, +) *MemberRemovedEvent { + + return &MemberRemovedEvent{ + MemberRemovedEvent: *member.NewRemovedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberRemovedEventType, + ), + userID, + ), + } +} diff --git a/internal/v2/repository/project/oidc_config.go b/internal/v2/repository/project/oidc_config.go new file mode 100644 index 0000000000..608e9ee58e --- /dev/null +++ b/internal/v2/repository/project/oidc_config.go @@ -0,0 +1,102 @@ +package project + +import ( + "context" + "encoding/json" + "time" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" + "github.com/caos/zitadel/internal/v2/domain" +) + +const ( + OIDCConfigAdded = applicationEventTypePrefix + "config.oidc.added" + OIDCConfigChanged = applicationEventTypePrefix + "config.oidc.changed" + OIDCConfigSecretChanged = applicationEventTypePrefix + "config.oidc.secret.changed" + OIDCClientSecretCheckSucceeded = applicationEventTypePrefix + "oidc.secret.check.succeeded" + OIDCClientSecretCheckFailed = applicationEventTypePrefix + "oidc.secret.check.failed" +) + +type OIDCConfigAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + Version domain.OIDCVersion `json:"oidcVersion,omitempty"` + AppID string `json:"appId"` + ClientID string `json:"clientId,omitempty"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` + RedirectUris []string `json:"redirectUris,omitempty"` + ResponseTypes []domain.OIDCResponseType `json:"responseTypes,omitempty"` + GrantTypes []domain.OIDCGrantType `json:"grantTypes,omitempty"` + ApplicationType domain.OIDCApplicationType `json:"applicationType,omitempty"` + AuthMethodType domain.OIDCAuthMethodType `json:"authMethodType,omitempty"` + PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"` + DevMode bool `json:"devMode,omitempty"` + AccessTokenType domain.OIDCTokenType `json:"accessTokenType,omitempty"` + AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion,omitempty"` + IDTokenRoleAssertion bool `json:"idTokenRoleAssertion,omitempty"` + IDTokenUserinfoAssertion bool `json:"idTokenUserinfoAssertion,omitempty"` + ClockSkew time.Duration `json:"clockSkew,omitempty"` +} + +func (e *OIDCConfigAddedEvent) Data() interface{} { + return e +} + +func NewOIDCConfigAddedEvent( + ctx context.Context, + version domain.OIDCVersion, + appID string, + clientID string, + clientSecret *crypto.CryptoValue, + redirectUris []string, + responseTypes []domain.OIDCResponseType, + grantTypes []domain.OIDCGrantType, + applicationType domain.OIDCApplicationType, + authMethodType domain.OIDCAuthMethodType, + postLogoutRedirectUris []string, + devMode bool, + accessTokenType domain.OIDCTokenType, + accessTokenRoleAssertion bool, + idTokenRoleAssertion bool, + idTokenUserinfoAssertion bool, + clockSkew time.Duration, +) *OIDCConfigAddedEvent { + return &OIDCConfigAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + OIDCConfigAdded, + ), + Version: version, + AppID: appID, + ClientID: clientID, + ClientSecret: clientSecret, + RedirectUris: redirectUris, + ResponseTypes: responseTypes, + GrantTypes: grantTypes, + ApplicationType: applicationType, + AuthMethodType: authMethodType, + PostLogoutRedirectUris: postLogoutRedirectUris, + DevMode: devMode, + AccessTokenType: accessTokenType, + AccessTokenRoleAssertion: accessTokenRoleAssertion, + IDTokenRoleAssertion: idTokenRoleAssertion, + IDTokenUserinfoAssertion: idTokenUserinfoAssertion, + ClockSkew: clockSkew, + } +} + +func OIDCConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &OIDCConfigAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-BFd15", "unable to unmarshal oidc config") + } + + return e, nil +} diff --git a/internal/v2/repository/project/project.go b/internal/v2/repository/project/project.go new file mode 100644 index 0000000000..6614c2bfe3 --- /dev/null +++ b/internal/v2/repository/project/project.go @@ -0,0 +1,54 @@ +package project + +import ( + "context" + "encoding/json" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +const ( + projectEventTypePrefix = eventstore.EventType("project.") + ProjectAdded = projectEventTypePrefix + "added" + ProjectChanged = projectEventTypePrefix + "changed" + ProjectDeactivated = projectEventTypePrefix + "deactivated" + ProjectReactivated = projectEventTypePrefix + "reactivated" + ProjectRemoved = projectEventTypePrefix + "removed" +) + +type ProjectAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + Name string `json:"name,omitempty"` + ProjectRoleAssertion bool `json:"projectRoleAssertion,omitempty"` + ProjectRoleCheck bool `json:"projectRoleCheck,omitempty"` +} + +func (e *ProjectAddedEvent) Data() interface{} { + return e +} + +func NewProjectAddedEvent(ctx context.Context, name string) *ProjectAddedEvent { + return &ProjectAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + ProjectAdded, + ), + Name: name, + } +} + +func ProjectAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ProjectAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "PROJECT-Bfg2f", "unable to unmarshal project") + } + + return e, nil +}