diff --git a/cmd/admin/setup/03.go b/cmd/admin/setup/03.go index 5fb2d3f8d..0cef02597 100644 --- a/cmd/admin/setup/03.go +++ b/cmd/admin/setup/03.go @@ -50,7 +50,6 @@ func (mig *DefaultInstance) Execute(ctx context.Context) error { mig.zitadelRoles, nil, nil, - nil, mig.externalDomain, mig.externalSecure, mig.externalPort, diff --git a/cmd/admin/start/config.go b/cmd/admin/start/config.go index fa45ec217..2550ae894 100644 --- a/cmd/admin/start/config.go +++ b/cmd/admin/start/config.go @@ -1,6 +1,8 @@ package start import ( + "time" + "github.com/mitchellh/mapstructure" "github.com/spf13/viper" "github.com/zitadel/logging" @@ -25,30 +27,31 @@ import ( ) type Config struct { - Log *logging.Config - Port uint16 - ExternalPort uint16 - ExternalDomain string - ExternalSecure bool - HTTP2HostHeader string - HTTP1HostHeader string - WebAuthNName string - Database database.Config - Tracing tracing.Config - Projections projection.Config - AuthZ authz.Config - Auth auth_es.Config - Admin admin_es.Config - UserAgentCookie *middleware.UserAgentCookieConfig - OIDC oidc.Config - Login login.Config - Console console.Config - Notification notification.Config - AssetStorage static_config.AssetStorageConfig - InternalAuthZ internal_authz.Config - SystemDefaults systemdefaults.SystemDefaults - EncryptionKeys *encryptionKeyConfig - DefaultInstance command.InstanceSetup + Log *logging.Config + Port uint16 + ExternalPort uint16 + ExternalDomain string + ExternalSecure bool + HTTP2HostHeader string + HTTP1HostHeader string + WebAuthNName string + Database database.Config + Tracing tracing.Config + Projections projection.Config + AuthZ authz.Config + Auth auth_es.Config + Admin admin_es.Config + UserAgentCookie *middleware.UserAgentCookieConfig + OIDC oidc.Config + Login login.Config + Console console.Config + Notification notification.Config + AssetStorage static_config.AssetStorageConfig + InternalAuthZ internal_authz.Config + SystemDefaults systemdefaults.SystemDefaults + EncryptionKeys *encryptionKeyConfig + DefaultInstance command.InstanceSetup + AuditLogRetention time.Duration } func MustNewConfig(v *viper.Viper) *Config { diff --git a/cmd/admin/start/start.go b/cmd/admin/start/start.go index d1f49d68a..8ac50f7a2 100644 --- a/cmd/admin/start/start.go +++ b/cmd/admin/start/start.go @@ -116,7 +116,6 @@ func startZitadel(config *Config, masterKey string) error { config.SystemDefaults, config.InternalAuthZ.RolePermissionMappings, storage, - authZRepo, webAuthNConfig, config.ExternalDomain, config.ExternalSecure, @@ -168,10 +167,10 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman if err := authenticatedAPIs.RegisterServer(ctx, admin.CreateServer(commands, queries, adminRepo, assets.HandlerPrefix, keys.User)); err != nil { return err } - if err := authenticatedAPIs.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, assets.HandlerPrefix, keys.User, config.ExternalSecure, oidc.HandlerPrefix)); err != nil { + if err := authenticatedAPIs.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, assets.HandlerPrefix, keys.User, config.ExternalSecure, oidc.HandlerPrefix, config.AuditLogRetention)); err != nil { return err } - if err := authenticatedAPIs.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, assets.HandlerPrefix, keys.User, config.ExternalSecure)); err != nil { + if err := authenticatedAPIs.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, assets.HandlerPrefix, keys.User, config.ExternalSecure, config.AuditLogRetention)); err != nil { return err } diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 4e9e76dfc..c02e9d7b9 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -228,29 +228,6 @@ DefaultInstance: IncludeUpperLetters: true IncludeDigits: true IncludeSymbols: false - Features: - TierName: Default Tier - TierDescription: "" - State: 1 #active - StateDescription: "" - Retention: 8760h #1year - LoginPolicyFactors: true - LoginPolicyIDP: true - LoginPolicyPasswordless: true - LoginPolicyRegistration: true - LoginPolicyUsernameLogin: true - LoginPolicyPasswordReset: true - PasswordComplexityPolicy: true - LabelPolicyPrivateLabel: true - LabelPolicyWatermark: true - CustomDomain: true - PrivacyPolicy: true - MetadataUser: true - CustomTextMessage: true - CustomTextLogin: true - LockoutPolicy: true - ActionsAllowed: 2 #ActionsAllowedUnlimited - MaxActions: #not necessary because of ActionsAllowedUnlimited PasswordComplexityPolicy: MinLength: 8 HasLowercase: true @@ -383,8 +360,6 @@ InternalAuthZ: Permissions: - "iam.read" - "iam.write" - - "iam.features.read" - - "iam.features.write" - "iam.policy.read" - "iam.policy.write" - "iam.policy.delete" @@ -425,7 +400,6 @@ InternalAuthZ: - "user.grant.delete" - "user.membership.read" - "user.credential.write" - - "features.read" - "policy.read" - "policy.write" - "policy.delete" @@ -451,7 +425,6 @@ InternalAuthZ: - Role: "IAM_OWNER_VIEWER" Permissions: - "iam.read" - - "iam.features.read" - "iam.policy.read" - "iam.member.read" - "iam.idp.read" @@ -466,7 +439,6 @@ InternalAuthZ: - "user.global.read" - "user.grant.read" - "user.membership.read" - - "features.read" - "policy.read" - "project.read" - "project.member.read" @@ -501,7 +473,6 @@ InternalAuthZ: - "user.grant.delete" - "user.membership.read" - "user.credential.write" - - "features.read" - "policy.read" - "policy.write" - "policy.delete" @@ -538,7 +509,6 @@ InternalAuthZ: - "user.grant.write" - "user.grant.delete" - "user.membership.read" - - "features.read" - "project.read" - "project.member.read" - "project.role.read" @@ -574,7 +544,6 @@ InternalAuthZ: - "user.grant.delete" - "user.membership.read" - "user.credential.write" - - "features.read" - "policy.read" - "policy.write" - "policy.delete" @@ -619,7 +588,6 @@ InternalAuthZ: - "user.global.read" - "user.grant.read" - "user.membership.read" - - "features.read" - "policy.read" - "project.read" - "project.member.read" diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 856286989..64995f2de 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -112,7 +112,6 @@ "NEWVALUE": "Neuer Wert", "RESTORE": "Wiederherstellen", "CONTINUEWITHOUTSAVE": "Ohne speichern fortfahren", - "GOTOFEATURES": "Zu den Features", "OF": "von", "PREVIOUS": "Zurück", "NEXT": "Weiter", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 3279e01b4..6583b0566 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -112,7 +112,6 @@ "NEWVALUE": "New Value", "RESTORE": "Restore", "CONTINUEWITHOUTSAVE": "Continue without saving", - "GOTOFEATURES": "Go to features", "OF": "of", "PREVIOUS": "Previous", "NEXT": "Next", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index 9c25a3619..247aba981 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -112,7 +112,6 @@ "NEWVALUE": "Nuovo valore", "RESTORE": "Ripristina", "CONTINUEWITHOUTSAVE": "Continua senza salvare", - "GOTOFEATURES": "Vai alle caratteristiche", "OF": "di", "PREVIOUS": "Precedente", "NEXT": "Avanti", diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md index 300300fdc..d45220f55 100644 --- a/docs/docs/apis/proto/admin.md +++ b/docs/docs/apis/proto/admin.md @@ -423,66 +423,6 @@ all fields are updated. If no value is provided the field will be empty afterwar PUT: /idps/{idp_id}/jwt_config -### GetDefaultFeatures - -> **rpc** GetDefaultFeatures([GetDefaultFeaturesRequest](#getdefaultfeaturesrequest)) -[GetDefaultFeaturesResponse](#getdefaultfeaturesresponse) - - - - - - GET: /features - - -### SetDefaultFeatures - -> **rpc** SetDefaultFeatures([SetDefaultFeaturesRequest](#setdefaultfeaturesrequest)) -[SetDefaultFeaturesResponse](#setdefaultfeaturesresponse) - - - - - - PUT: /features - - -### GetOrgFeatures - -> **rpc** GetOrgFeatures([GetOrgFeaturesRequest](#getorgfeaturesrequest)) -[GetOrgFeaturesResponse](#getorgfeaturesresponse) - - - - - - GET: /orgs/{org_id}/features - - -### SetOrgFeatures - -> **rpc** SetOrgFeatures([SetOrgFeaturesRequest](#setorgfeaturesrequest)) -[SetOrgFeaturesResponse](#setorgfeaturesresponse) - - - - - - PUT: /orgs/{org_id}/features - - -### ResetOrgFeatures - -> **rpc** ResetOrgFeatures([ResetOrgFeaturesRequest](#resetorgfeaturesrequest)) -[ResetOrgFeaturesResponse](#resetorgfeaturesresponse) - - - - - - DELETE: /orgs/{org_id}/features - - ### GetOrgIAMPolicy > **rpc** GetOrgIAMPolicy([GetOrgIAMPolicyRequest](#getorgiampolicyrequest)) @@ -1962,23 +1902,6 @@ This is an empty request -### GetDefaultFeaturesRequest - - - - - -### GetDefaultFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| features | zitadel.features.v1.Features | - | | - - - - ### GetDefaultInitMessageTextRequest @@ -2291,28 +2214,6 @@ This is an empty request -### GetOrgFeaturesRequest - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| org_id | string | - | string.min_len: 1
string.max_len: 200
| - - - - -### GetOrgFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| features | zitadel.features.v1.Features | - | | - - - - ### GetOrgIAMPolicyRequest @@ -3217,28 +3118,6 @@ This is an empty request -### ResetOrgFeaturesRequest - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| org_id | string | - | string.min_len: 1
string.max_len: 200
| - - - - -### ResetOrgFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| details | zitadel.v1.ObjectDetails | - | | - - - - ### SetCustomLoginTextsRequest @@ -3324,50 +3203,6 @@ This is an empty request -### SetDefaultFeaturesRequest - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| tier_name | string | - | string.max_len: 200
| -| description | string | - | string.max_len: 200
| -| audit_log_retention | google.protobuf.Duration | - | duration.gte.seconds: 0
duration.gte.nanos: 0
| -| login_policy_username_login | bool | - | | -| login_policy_registration | bool | - | | -| login_policy_idp | bool | - | | -| login_policy_factors | bool | - | | -| login_policy_passwordless | bool | - | | -| password_complexity_policy | bool | - | | -| label_policy | bool | - | | -| custom_domain | bool | - | | -| login_policy_password_reset | bool | - | | -| label_policy_private_label | bool | - | | -| label_policy_watermark | bool | - | | -| custom_text | bool | - | | -| privacy_policy | bool | - | | -| metadata_user | bool | - | | -| custom_text_message | bool | - | | -| custom_text_login | bool | - | | -| lockout_policy | bool | - | | -| actions | bool | - | | -| actions_allowed | zitadel.features.v1.ActionsAllowed | - | | -| max_actions | int32 | - | | - - - - -### SetDefaultFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| details | zitadel.v1.ObjectDetails | - | | - - - - ### SetDefaultInitMessageTextRequest @@ -3535,53 +3370,6 @@ This is an empty request -### SetOrgFeaturesRequest - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| org_id | string | - | string.min_len: 1
string.max_len: 200
| -| tier_name | string | - | string.max_len: 200
| -| description | string | - | string.max_len: 200
| -| state | zitadel.features.v1.FeaturesState | - | | -| state_description | string | - | string.max_len: 200
| -| audit_log_retention | google.protobuf.Duration | - | duration.gte.seconds: 0
duration.gte.nanos: 0
| -| login_policy_username_login | bool | - | | -| login_policy_registration | bool | - | | -| login_policy_idp | bool | - | | -| login_policy_factors | bool | - | | -| login_policy_passwordless | bool | - | | -| password_complexity_policy | bool | - | | -| label_policy | bool | - | | -| custom_domain | bool | - | | -| login_policy_password_reset | bool | - | | -| label_policy_private_label | bool | - | | -| label_policy_watermark | bool | - | | -| custom_text | bool | - | | -| privacy_policy | bool | - | | -| metadata_user | bool | - | | -| custom_text_message | bool | - | | -| custom_text_login | bool | - | | -| lockout_policy | bool | - | | -| actions | bool | - | | -| actions_allowed | zitadel.features.v1.ActionsAllowed | - | | -| max_actions | int32 | - | | - - - - -### SetOrgFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| details | zitadel.v1.ObjectDetails | - | | - - - - ### SetUpOrgRequest diff --git a/docs/docs/apis/proto/auth.md b/docs/docs/apis/proto/auth.md index 5d576d0a9..6a580b2e1 100644 --- a/docs/docs/apis/proto/auth.md +++ b/docs/docs/apis/proto/auth.md @@ -533,18 +533,6 @@ Returns a list of organisations where the authorized user has a user grant (auth POST: /global/projectorgs/_search -### ListMyZitadelFeatures - -> **rpc** ListMyZitadelFeatures([ListMyZitadelFeaturesRequest](#listmyzitadelfeaturesrequest)) -[ListMyZitadelFeaturesResponse](#listmyzitadelfeaturesresponse) - -Returns a list of features, which are allowed on these organisation based on the subscription of the organisation - - - - POST: /features/zitadel/me/_search - - ### ListMyZitadelPermissions > **rpc** ListMyZitadelPermissions([ListMyZitadelPermissionsRequest](#listmyzitadelpermissionsrequest)) @@ -1087,23 +1075,6 @@ This is an empty request -### ListMyZitadelFeaturesRequest -This is an empty request - - - - -### ListMyZitadelFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| result | repeated string | - | | - - - - ### ListMyZitadelPermissionsRequest This is an empty request diff --git a/docs/docs/apis/proto/features.md b/docs/docs/apis/proto/features.md deleted file mode 100644 index 8970ca333..000000000 --- a/docs/docs/apis/proto/features.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: zitadel/features.proto ---- - - - - - - -## Enums - - -### FeaturesState {#featuresstate} - - -| Name | Number | Description | -| ---- | ------ | ----------- | -| FEATURES_STATE_ACTIVE | 0 | - | -| FEATURES_STATE_ACTION_REQUIRED | 1 | - | -| FEATURES_STATE_CANCELED | 2 | - | -| FEATURES_STATE_GRANDFATHERED | 3 | - | - - - - diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md index a49e8fd68..f9cd9b7b0 100644 --- a/docs/docs/apis/proto/management.md +++ b/docs/docs/apis/proto/management.md @@ -1680,18 +1680,6 @@ remove a list of user grants in one request DELETE: /user_grants/_bulk -### GetFeatures - -> **rpc** GetFeatures([GetFeaturesRequest](#getfeaturesrequest)) -[GetFeaturesResponse](#getfeaturesresponse) - - - - - - GET: /features - - ### GetOrgIAMPolicy > **rpc** GetOrgIAMPolicy([GetOrgIAMPolicyRequest](#getorgiampolicyrequest)) @@ -4570,23 +4558,6 @@ This is an empty request -### GetFeaturesRequest - - - - - -### GetFeaturesResponse - - - -| Field | Type | Description | Validation | -| ----- | ---- | ----------- | ----------- | -| features | zitadel.features.v1.Features | - | | - - - - ### GetFlowRequest diff --git a/docs/docs/apis/proto/options.md b/docs/docs/apis/proto/options.md index c175a172b..4270bc94d 100644 --- a/docs/docs/apis/proto/options.md +++ b/docs/docs/apis/proto/options.md @@ -17,7 +17,6 @@ title: zitadel/options.proto | ----- | ---- | ----------- | ----------- | | permission | string | - | | | check_field_name | string | - | | -| feature | string | - | | diff --git a/internal/api/assets/generator/asset.yaml b/internal/api/assets/generator/asset.yaml index cefb90d20..6076882b1 100644 --- a/internal/api/assets/generator/asset.yaml +++ b/internal/api/assets/generator/asset.yaml @@ -54,7 +54,6 @@ Services: Methods: OrgLabelPolicyLogo: Path: "/policy/label/logo" - Feature: "label_policy.private_label" HasDarkMode: true Handlers: - Name: Upload @@ -71,7 +70,6 @@ Services: Permission: policy.read OrgLabelPolicyIcon: Path: "/policy/label/icon" - Feature: "label_policy.private_label" HasDarkMode: true Handlers: - Name: Upload @@ -88,7 +86,6 @@ Services: Permission: policy.read OrgLabelPolicyFont: Path: "/policy/label/font" - Feature: "label_policy.private_label" Handlers: - Name: Upload Comment: @@ -107,7 +104,6 @@ Services: Methods: MyUserAvatar: Path: "/me/avatar" - Features: "label_policy.private_label" Handlers: - Name: Upload Comment: diff --git a/internal/api/assets/generator/asset_generator.go b/internal/api/assets/generator/asset_generator.go index 867e194bb..a30112a82 100644 --- a/internal/api/assets/generator/asset_generator.go +++ b/internal/api/assets/generator/asset_generator.go @@ -31,7 +31,6 @@ func main() { type Method struct { Path string - Feature string HasDarkMode bool Handlers []Handler } @@ -144,15 +143,13 @@ var {{.Name}}_AuthMethods = authz.MethodMapping { {{ range $service := .Services}} {{ range $method := .Methods}} {{ range $handler := .Handlers}} - {{ if (or $method.Feature $handler.Permission) }} + {{ if $handler.Permission }} "{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}": authz.Option{ Permission: "{{$handler.Permission}}", - Feature: "{{$method.Feature}}", }, {{ if $method.HasDarkMode }} "{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}": authz.Option{ Permission: "{{$handler.Permission}}", - Feature: "{{$method.Feature}}", }, {{end}} {{end}} diff --git a/internal/api/authz/authorization.go b/internal/api/authz/authorization.go index 349522d3b..c3c6d55d4 100644 --- a/internal/api/authz/authorization.go +++ b/internal/api/authz/authorization.go @@ -23,13 +23,6 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID s return nil, err } - if requiredAuthOption.Feature != "" { - err = CheckOrgFeatures(ctx, verifier, ctxData.OrgID, requiredAuthOption.Feature) - if err != nil { - return nil, err - } - } - if requiredAuthOption.Permission == authenticated { return func(parent context.Context) context.Context { return context.WithValue(parent, dataKey, ctxData) @@ -56,10 +49,6 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID s }, nil } -func CheckOrgFeatures(ctx context.Context, t *TokenVerifier, orgID string, requiredFeatures ...string) error { - return t.authZRepo.CheckOrgFeatures(ctx, orgID, requiredFeatures...) -} - func checkUserPermissions(req interface{}, userPerms []string, authOpt Option) error { if len(userPerms) == 0 { return errors.ThrowPermissionDenied(nil, "AUTH-5mWD2", "No matching permissions found") diff --git a/internal/api/authz/permissions_test.go b/internal/api/authz/permissions_test.go index 35a6615da..74b9d50ff 100644 --- a/internal/api/authz/permissions_test.go +++ b/internal/api/authz/permissions_test.go @@ -34,10 +34,6 @@ func (v *testVerifier) VerifierClientID(ctx context.Context, appName string) (st return "clientID", "projectID", nil } -func (v *testVerifier) CheckOrgFeatures(context.Context, string, ...string) error { - return nil -} - func equalStringArray(a, b []string) bool { if len(a) != len(b) { return false diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go index fdc7aced3..eae35b52e 100644 --- a/internal/api/authz/token.go +++ b/internal/api/authz/token.go @@ -25,7 +25,6 @@ type authZRepo interface { SearchMyMemberships(ctx context.Context) ([]*Membership, error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) ExistsOrg(ctx context.Context, orgID string) error - CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error } func Start(authZRepo authZRepo) (v *TokenVerifier) { diff --git a/internal/api/grpc/admin/features.go b/internal/api/grpc/admin/features.go deleted file mode 100644 index 7a6f0c8e5..000000000 --- a/internal/api/grpc/admin/features.go +++ /dev/null @@ -1,120 +0,0 @@ -package admin - -import ( - "context" - - features_grpc "github.com/zitadel/zitadel/internal/api/grpc/features" - object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object" - "github.com/zitadel/zitadel/internal/domain" - admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin" -) - -func (s *Server) GetDefaultFeatures(ctx context.Context, _ *admin_pb.GetDefaultFeaturesRequest) (*admin_pb.GetDefaultFeaturesResponse, error) { - features, err := s.query.DefaultFeatures(ctx) - if err != nil { - return nil, err - } - return &admin_pb.GetDefaultFeaturesResponse{ - Features: features_grpc.ModelFeaturesToPb(features), - }, nil -} - -func (s *Server) SetDefaultFeatures(ctx context.Context, req *admin_pb.SetDefaultFeaturesRequest) (*admin_pb.SetDefaultFeaturesResponse, error) { - details, err := s.command.SetDefaultFeatures(ctx, setDefaultFeaturesRequestToDomain(req)) - if err != nil { - return nil, err - } - return &admin_pb.SetDefaultFeaturesResponse{ - Details: object_grpc.DomainToChangeDetailsPb(details), - }, nil -} - -func (s *Server) GetOrgFeatures(ctx context.Context, req *admin_pb.GetOrgFeaturesRequest) (*admin_pb.GetOrgFeaturesResponse, error) { - features, err := s.query.FeaturesByOrgID(ctx, req.OrgId) - if err != nil { - return nil, err - } - return &admin_pb.GetOrgFeaturesResponse{ - Features: features_grpc.ModelFeaturesToPb(features), - }, nil -} - -func (s *Server) SetOrgFeatures(ctx context.Context, req *admin_pb.SetOrgFeaturesRequest) (*admin_pb.SetOrgFeaturesResponse, error) { - details, err := s.command.SetOrgFeatures(ctx, req.OrgId, setOrgFeaturesRequestToDomain(req)) - if err != nil { - return nil, err - } - return &admin_pb.SetOrgFeaturesResponse{ - Details: object_grpc.DomainToChangeDetailsPb(details), - }, nil -} - -func (s *Server) ResetOrgFeatures(ctx context.Context, req *admin_pb.ResetOrgFeaturesRequest) (*admin_pb.ResetOrgFeaturesResponse, error) { - details, err := s.command.RemoveOrgFeatures(ctx, req.OrgId) - if err != nil { - return nil, err - } - return &admin_pb.ResetOrgFeaturesResponse{ - Details: object_grpc.DomainToChangeDetailsPb(details), - }, nil -} - -func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest) *domain.Features { - actionsAllowed := features_grpc.ActionsAllowedToDomain(req.ActionsAllowed) - if req.Actions { - actionsAllowed = domain.ActionsAllowedUnlimited - } - return &domain.Features{ - TierName: req.TierName, - TierDescription: req.Description, - AuditLogRetention: req.AuditLogRetention.AsDuration(), - LoginPolicyFactors: req.LoginPolicyFactors, - LoginPolicyIDP: req.LoginPolicyIdp, - LoginPolicyPasswordless: req.LoginPolicyPasswordless, - LoginPolicyRegistration: req.LoginPolicyRegistration, - LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin, - LoginPolicyPasswordReset: req.LoginPolicyPasswordReset, - PasswordComplexityPolicy: req.PasswordComplexityPolicy, - LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel, - LabelPolicyWatermark: req.LabelPolicyWatermark, - CustomDomain: req.CustomDomain, - PrivacyPolicy: req.PrivacyPolicy, - MetadataUser: req.MetadataUser, - CustomTextLogin: req.CustomTextLogin || req.CustomText, - CustomTextMessage: req.CustomTextMessage, - LockoutPolicy: req.LockoutPolicy, - ActionsAllowed: actionsAllowed, - MaxActions: int(req.MaxActions), - } -} - -func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.Features { - actionsAllowed := features_grpc.ActionsAllowedToDomain(req.ActionsAllowed) - if req.Actions { - actionsAllowed = domain.ActionsAllowedUnlimited - } - return &domain.Features{ - TierName: req.TierName, - TierDescription: req.Description, - State: features_grpc.FeaturesStateToDomain(req.State), - StateDescription: req.StateDescription, - AuditLogRetention: req.AuditLogRetention.AsDuration(), - LoginPolicyFactors: req.LoginPolicyFactors, - LoginPolicyIDP: req.LoginPolicyIdp, - LoginPolicyPasswordless: req.LoginPolicyPasswordless, - LoginPolicyRegistration: req.LoginPolicyRegistration, - LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin, - LoginPolicyPasswordReset: req.LoginPolicyPasswordReset, - PasswordComplexityPolicy: req.PasswordComplexityPolicy, - LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel, - LabelPolicyWatermark: req.LabelPolicyWatermark, - CustomDomain: req.CustomDomain, - PrivacyPolicy: req.PrivacyPolicy, - MetadataUser: req.MetadataUser, - CustomTextLogin: req.CustomTextLogin || req.CustomText, - CustomTextMessage: req.CustomTextMessage, - LockoutPolicy: req.LockoutPolicy, - ActionsAllowed: actionsAllowed, - MaxActions: int(req.MaxActions), - } -} diff --git a/internal/api/grpc/auth/features.go b/internal/api/grpc/auth/features.go deleted file mode 100644 index 86beea81f..000000000 --- a/internal/api/grpc/auth/features.go +++ /dev/null @@ -1,18 +0,0 @@ -package auth - -import ( - "context" - - "github.com/zitadel/zitadel/internal/api/authz" - auth_pb "github.com/zitadel/zitadel/pkg/grpc/auth" -) - -func (s *Server) ListMyZitadelFeatures(ctx context.Context, _ *auth_pb.ListMyZitadelFeaturesRequest) (*auth_pb.ListMyZitadelFeaturesResponse, error) { - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - return &auth_pb.ListMyZitadelFeaturesResponse{ - Result: features.EnabledFeatureTypes(), - }, nil -} diff --git a/internal/api/grpc/auth/server.go b/internal/api/grpc/auth/server.go index 6d7aaf6e7..40697a825 100644 --- a/internal/api/grpc/auth/server.go +++ b/internal/api/grpc/auth/server.go @@ -1,6 +1,8 @@ package auth import ( + "time" + "google.golang.org/grpc" "github.com/zitadel/zitadel/internal/api/authz" @@ -22,13 +24,14 @@ const ( type Server struct { auth.UnimplementedAuthServiceServer - command *command.Commands - query *query.Queries - repo repository.Repository - defaults systemdefaults.SystemDefaults - assetsAPIDomain string - userCodeAlg crypto.EncryptionAlgorithm - externalSecure bool + command *command.Commands + query *query.Queries + repo repository.Repository + defaults systemdefaults.SystemDefaults + assetsAPIDomain string + userCodeAlg crypto.EncryptionAlgorithm + externalSecure bool + auditLogRetention time.Duration } type Config struct { @@ -42,15 +45,17 @@ func CreateServer(command *command.Commands, assetsAPIDomain string, userCodeAlg crypto.EncryptionAlgorithm, externalSecure bool, + auditLogRetention time.Duration, ) *Server { return &Server{ - command: command, - query: query, - repo: authRepo, - defaults: defaults, - assetsAPIDomain: assetsAPIDomain, - userCodeAlg: userCodeAlg, - externalSecure: externalSecure, + command: command, + query: query, + repo: authRepo, + defaults: defaults, + assetsAPIDomain: assetsAPIDomain, + userCodeAlg: userCodeAlg, + externalSecure: externalSecure, + auditLogRetention: auditLogRetention, } } diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index cb343d512..849dd5bd0 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -56,11 +56,7 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques func (s *Server) ListMyUserChanges(ctx context.Context, req *auth_pb.ListMyUserChangesRequest) (*auth_pb.ListMyUserChangesResponse, error) { sequence, limit, asc := change.ChangeQueryToQuery(req.Query) - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).ResourceOwner) - if err != nil { - return nil, err - } - changes, err := s.query.UserChanges(ctx, authz.GetCtxData(ctx).UserID, sequence, limit, asc, features.AuditLogRetention) + changes, err := s.query.UserChanges(ctx, authz.GetCtxData(ctx).UserID, sequence, limit, asc, s.auditLogRetention) if err != nil { return nil, err } diff --git a/internal/api/grpc/features/features.go b/internal/api/grpc/features/features.go deleted file mode 100644 index c0fca629f..000000000 --- a/internal/api/grpc/features/features.go +++ /dev/null @@ -1,108 +0,0 @@ -package features - -import ( - "google.golang.org/protobuf/types/known/durationpb" - - object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object" - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/query" - features_pb "github.com/zitadel/zitadel/pkg/grpc/features" -) - -func ModelFeaturesToPb(features *query.Features) *features_pb.Features { - return &features_pb.Features{ - IsDefault: features.IsDefault, - Tier: FeatureTierToPb(features.TierName, features.TierDescription, features.State, features.StateDescription), - AuditLogRetention: durationpb.New(features.AuditLogRetention), - LoginPolicyFactors: features.LoginPolicyFactors, - LoginPolicyIdp: features.LoginPolicyIDP, - LoginPolicyPasswordless: features.LoginPolicyPasswordless, - LoginPolicyRegistration: features.LoginPolicyRegistration, - LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin, - LoginPolicyPasswordReset: features.LoginPolicyPasswordReset, - PasswordComplexityPolicy: features.PasswordComplexityPolicy, - LabelPolicy: features.LabelPolicyPrivateLabel, - CustomDomain: features.CustomDomain, - LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel, - LabelPolicyWatermark: features.LabelPolicyWatermark, - PrivacyPolicy: features.PrivacyPolicy, - CustomText: features.CustomTextMessage, - CustomTextMessage: features.CustomTextMessage, - CustomTextLogin: features.CustomTextLogin, - MetadataUser: features.MetadataUser, - LockoutPolicy: features.LockoutPolicy, - Actions: features.ActionsAllowed != domain.ActionsNotAllowed, - ActionsAllowed: ActionsAllowedToPb(features.ActionsAllowed), - MaxActions: features.MaxActions, - Details: object_grpc.ChangeToDetailsPb( - features.Sequence, - features.ChangeDate, - features.AggregateID, - ), - } -} - -func FeatureTierToPb(name, description string, status domain.FeaturesState, statusDescription string) *features_pb.FeatureTier { - return &features_pb.FeatureTier{ - Name: name, - Description: description, - State: FeaturesStateToPb(status), - StatusInfo: statusDescription, - } -} - -func FeaturesStateToPb(status domain.FeaturesState) features_pb.FeaturesState { - switch status { - case domain.FeaturesStateActive: - return features_pb.FeaturesState_FEATURES_STATE_ACTIVE - case domain.FeaturesStateActionRequired: - return features_pb.FeaturesState_FEATURES_STATE_ACTION_REQUIRED - case domain.FeaturesStateCanceled: - return features_pb.FeaturesState_FEATURES_STATE_CANCELED - case domain.FeaturesStateGrandfathered: - return features_pb.FeaturesState_FEATURES_STATE_GRANDFATHERED - default: - return features_pb.FeaturesState_FEATURES_STATE_ACTIVE - } -} - -func FeaturesStateToDomain(status features_pb.FeaturesState) domain.FeaturesState { - switch status { - case features_pb.FeaturesState_FEATURES_STATE_ACTIVE: - return domain.FeaturesStateActive - case features_pb.FeaturesState_FEATURES_STATE_ACTION_REQUIRED: - return domain.FeaturesStateActionRequired - case features_pb.FeaturesState_FEATURES_STATE_CANCELED: - return domain.FeaturesStateCanceled - case features_pb.FeaturesState_FEATURES_STATE_GRANDFATHERED: - return domain.FeaturesStateGrandfathered - default: - return -1 - } -} - -func ActionsAllowedToDomain(allowed features_pb.ActionsAllowed) domain.ActionsAllowed { - switch allowed { - case features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED: - return domain.ActionsNotAllowed - case features_pb.ActionsAllowed_ACTIONS_ALLOWED_MAX: - return domain.ActionsMaxAllowed - case features_pb.ActionsAllowed_ACTIONS_ALLOWED_UNLIMITED: - return domain.ActionsAllowedUnlimited - default: - return domain.ActionsNotAllowed - } -} - -func ActionsAllowedToPb(allowed domain.ActionsAllowed) features_pb.ActionsAllowed { - switch allowed { - case domain.ActionsNotAllowed: - return features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED - case domain.ActionsMaxAllowed: - return features_pb.ActionsAllowed_ACTIONS_ALLOWED_MAX - case domain.ActionsAllowedUnlimited: - return features_pb.ActionsAllowed_ACTIONS_ALLOWED_UNLIMITED - default: - return features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED - } -} diff --git a/internal/api/grpc/management/features.go b/internal/api/grpc/management/features.go deleted file mode 100644 index 57e2568de..000000000 --- a/internal/api/grpc/management/features.go +++ /dev/null @@ -1,19 +0,0 @@ -package management - -import ( - "context" - - "github.com/zitadel/zitadel/internal/api/authz" - features_grpc "github.com/zitadel/zitadel/internal/api/grpc/features" - mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management" -) - -func (s *Server) GetFeatures(ctx context.Context, req *mgmt_pb.GetFeaturesRequest) (*mgmt_pb.GetFeaturesResponse, error) { - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - return &mgmt_pb.GetFeaturesResponse{ - Features: features_grpc.ModelFeaturesToPb(features), - }, nil -} diff --git a/internal/api/grpc/management/org.go b/internal/api/grpc/management/org.go index 976d63f9e..6637e9835 100644 --- a/internal/api/grpc/management/org.go +++ b/internal/api/grpc/management/org.go @@ -34,11 +34,7 @@ func (s *Server) GetOrgByDomainGlobal(ctx context.Context, req *mgmt_pb.GetOrgBy func (s *Server) ListOrgChanges(ctx context.Context, req *mgmt_pb.ListOrgChangesRequest) (*mgmt_pb.ListOrgChangesResponse, error) { sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query) - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - response, err := s.query.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, sequence, limit, asc, features.AuditLogRetention) + response, err := s.query.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, sequence, limit, asc, s.auditLogRetention) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/project.go b/internal/api/grpc/management/project.go index f214aa205..a17be02ef 100644 --- a/internal/api/grpc/management/project.go +++ b/internal/api/grpc/management/project.go @@ -111,11 +111,7 @@ func (s *Server) ListGrantedProjectRoles(ctx context.Context, req *mgmt_pb.ListG func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjectChangesRequest) (*mgmt_pb.ListProjectChangesResponse, error) { sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query) - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - res, err := s.query.ProjectChanges(ctx, req.ProjectId, sequence, limit, asc, features.AuditLogRetention) + res, err := s.query.ProjectChanges(ctx, req.ProjectId, sequence, limit, asc, s.auditLogRetention) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/project_application.go b/internal/api/grpc/management/project_application.go index 28e9b96bf..4e2d26990 100644 --- a/internal/api/grpc/management/project_application.go +++ b/internal/api/grpc/management/project_application.go @@ -44,11 +44,7 @@ func (s *Server) ListApps(ctx context.Context, req *mgmt_pb.ListAppsRequest) (*m func (s *Server) ListAppChanges(ctx context.Context, req *mgmt_pb.ListAppChangesRequest) (*mgmt_pb.ListAppChangesResponse, error) { sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query) - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - res, err := s.query.ApplicationChanges(ctx, req.ProjectId, req.AppId, sequence, limit, asc, features.AuditLogRetention) + res, err := s.query.ApplicationChanges(ctx, req.ProjectId, req.AppId, sequence, limit, asc, s.auditLogRetention) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/server.go b/internal/api/grpc/management/server.go index 46de35795..d3593b3d2 100644 --- a/internal/api/grpc/management/server.go +++ b/internal/api/grpc/management/server.go @@ -1,6 +1,8 @@ package management import ( + "time" + "google.golang.org/grpc" "github.com/zitadel/zitadel/internal/api/authz" @@ -20,14 +22,15 @@ var _ management.ManagementServiceServer = (*Server)(nil) type Server struct { management.UnimplementedManagementServiceServer - command *command.Commands - query *query.Queries - systemDefaults systemdefaults.SystemDefaults - assetAPIPrefix string - passwordHashAlg crypto.HashAlgorithm - userCodeAlg crypto.EncryptionAlgorithm - externalSecure bool - issuerPath string + command *command.Commands + query *query.Queries + systemDefaults systemdefaults.SystemDefaults + assetAPIPrefix string + passwordHashAlg crypto.HashAlgorithm + userCodeAlg crypto.EncryptionAlgorithm + externalSecure bool + issuerPath string + auditLogRetention time.Duration } func CreateServer( @@ -38,16 +41,18 @@ func CreateServer( userCodeAlg crypto.EncryptionAlgorithm, externalSecure bool, issuerPath string, + auditLogRetention time.Duration, ) *Server { return &Server{ - command: command, - query: query, - systemDefaults: sd, - assetAPIPrefix: assetAPIPrefix, - passwordHashAlg: crypto.NewBCrypt(sd.SecretGenerators.PasswordSaltCost), - userCodeAlg: userCodeAlg, - externalSecure: externalSecure, - issuerPath: issuerPath, + command: command, + query: query, + systemDefaults: sd, + assetAPIPrefix: assetAPIPrefix, + passwordHashAlg: crypto.NewBCrypt(sd.SecretGenerators.PasswordSaltCost), + userCodeAlg: userCodeAlg, + externalSecure: externalSecure, + issuerPath: issuerPath, + auditLogRetention: auditLogRetention, } } diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index a4dfd5943..b9fceb954 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -79,11 +79,7 @@ func (s *Server) ListUsers(ctx context.Context, req *mgmt_pb.ListUsersRequest) ( func (s *Server) ListUserChanges(ctx context.Context, req *mgmt_pb.ListUserChangesRequest) (*mgmt_pb.ListUserChangesResponse, error) { sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query) - features, err := s.query.FeaturesByOrgID(ctx, authz.GetCtxData(ctx).OrgID) - if err != nil { - return nil, err - } - res, err := s.query.UserChanges(ctx, req.UserId, sequence, limit, asc, features.AuditLogRetention) + res, err := s.query.UserChanges(ctx, req.UserId, sequence, limit, asc, s.auditLogRetention) if err != nil { return nil, err } diff --git a/internal/api/grpc/server/middleware/auth_interceptor_test.go b/internal/api/grpc/server/middleware/auth_interceptor_test.go index 3ab740989..cce501895 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor_test.go +++ b/internal/api/grpc/server/middleware/auth_interceptor_test.go @@ -37,9 +37,6 @@ func (v *verifierMock) ExistsOrg(ctx context.Context, orgID string) error { func (v *verifierMock) VerifierClientID(ctx context.Context, appName string) (string, string, error) { return "", "", nil } -func (v *verifierMock) CheckOrgFeatures(context.Context, string, ...string) error { - return nil -} func Test_authorize(t *testing.T) { type args struct { diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index b4f35e570..60a50b6ed 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -11,7 +11,6 @@ import ( "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/authz/repository/eventsourcing/view" "github.com/zitadel/zitadel/internal/crypto" - "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" v1 "github.com/zitadel/zitadel/internal/eventstore/v1" "github.com/zitadel/zitadel/internal/eventstore/v1/models" @@ -105,133 +104,6 @@ func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context return app.ProjectID, app.OIDCConfig.AllowedOrigins, nil } -func (repo *TokenVerifierRepo) CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error { - features, err := repo.Query.FeaturesByOrgID(ctx, orgID) - if err != nil { - return err - } - return checkFeatures(features, requiredFeatures...) -} - -func checkFeatures(features *query.Features, requiredFeatures ...string) error { - for _, requiredFeature := range requiredFeatures { - if strings.HasPrefix(requiredFeature, domain.FeatureLoginPolicy) { - if err := checkLoginPolicyFeatures(features, requiredFeature); err != nil { - return err - } - continue - } - if requiredFeature == domain.FeaturePasswordComplexityPolicy { - if !features.PasswordComplexityPolicy { - return MissingFeatureErr(requiredFeature) - } - continue - } - if strings.HasPrefix(requiredFeature, domain.FeatureLabelPolicy) { - if err := checkLabelPolicyFeatures(features, requiredFeature); err != nil { - return err - } - continue - } - if requiredFeature == domain.FeatureCustomDomain { - if !features.CustomDomain { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeatureCustomTextMessage { - if !features.CustomTextMessage { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeatureCustomTextLogin { - if !features.CustomTextLogin { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeaturePrivacyPolicy { - if !features.PrivacyPolicy { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeatureLockoutPolicy { - if !features.LockoutPolicy { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeatureMetadataUser { - if !features.MetadataUser { - return MissingFeatureErr(requiredFeature) - } - continue - } - if requiredFeature == domain.FeatureActions { - if features.ActionsAllowed == domain.ActionsNotAllowed { - return MissingFeatureErr(requiredFeature) - } - continue - } - return MissingFeatureErr(requiredFeature) - } - return nil -} - -func checkLoginPolicyFeatures(features *query.Features, requiredFeature string) error { - switch requiredFeature { - case domain.FeatureLoginPolicyFactors: - if !features.LoginPolicyFactors { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLoginPolicyIDP: - if !features.LoginPolicyIDP { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLoginPolicyPasswordless: - if !features.LoginPolicyPasswordless { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLoginPolicyRegistration: - if !features.LoginPolicyRegistration { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLoginPolicyUsernameLogin: - if !features.LoginPolicyUsernameLogin { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLoginPolicyPasswordReset: - if !features.LoginPolicyPasswordReset { - return MissingFeatureErr(requiredFeature) - } - default: - if !features.LoginPolicyFactors && !features.LoginPolicyIDP && !features.LoginPolicyPasswordless && !features.LoginPolicyRegistration && !features.LoginPolicyUsernameLogin { - return MissingFeatureErr(requiredFeature) - } - } - return nil -} - -func checkLabelPolicyFeatures(features *query.Features, requiredFeature string) error { - switch requiredFeature { - case domain.FeatureLabelPolicyPrivateLabel: - if !features.LabelPolicyPrivateLabel { - return MissingFeatureErr(requiredFeature) - } - case domain.FeatureLabelPolicyWatermark: - if !features.LabelPolicyWatermark { - return MissingFeatureErr(requiredFeature) - } - } - return nil -} - -func MissingFeatureErr(feature string) error { - return caos_errs.ThrowPermissionDeniedf(nil, "AUTH-Dvgsf", "missing feature %v", feature) -} - func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName string) (clientID, projectID string, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() diff --git a/internal/authz/repository/token_verifier.go b/internal/authz/repository/token_verifier.go index c9bcf30a1..c62c75427 100644 --- a/internal/authz/repository/token_verifier.go +++ b/internal/authz/repository/token_verifier.go @@ -7,6 +7,5 @@ import ( type TokenVerifierRepository interface { VerifyAccessToken(ctx context.Context, tokenString, verifierClientID, projectID string) (userID string, agentID string, clientID, prefLang, resourceOwner string, err error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) - CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error VerifierClientID(ctx context.Context, appName string) (clientID, projectID string, err error) } diff --git a/internal/command/command.go b/internal/command/command.go index 43749b64e..911fef0be 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -1,12 +1,10 @@ package command import ( - "context" "time" "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/http" - authz_repo "github.com/zitadel/zitadel/internal/authz/repository" sd "github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" @@ -50,19 +48,12 @@ type Commands struct { keyAlgorithm crypto.EncryptionAlgorithm privateKeyLifetime time.Duration publicKeyLifetime time.Duration - - tokenVerifier orgFeatureChecker -} - -type orgFeatureChecker interface { - CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error } func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, zitadelRoles []authz.RoleMapping, staticStore static.Storage, - authZRepo authz_repo.Repository, webAuthN *webauthn_helper.Config, externalDomain string, externalSecure bool, @@ -119,8 +110,6 @@ func StartCommands(es *eventstore.Eventstore, repo.domainVerificationGenerator = crypto.NewEncryptionGenerator(defaults.DomainVerification.VerificationGenerator, repo.domainVerificationAlg) repo.domainVerificationValidator = http.ValidateDomain - - repo.tokenVerifier = authZRepo return repo, nil } diff --git a/internal/command/features_model.go b/internal/command/features_model.go deleted file mode 100644 index 1b7e6029b..000000000 --- a/internal/command/features_model.go +++ /dev/null @@ -1,123 +0,0 @@ -package command - -import ( - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/features" -) - -type FeaturesWriteModel struct { - eventstore.WriteModel - - TierName string - TierDescription string - State domain.FeaturesState - StateDescription string - AuditLogRetention time.Duration - LoginPolicyFactors bool - LoginPolicyIDP bool - LoginPolicyPasswordless bool - LoginPolicyRegistration bool - LoginPolicyUsernameLogin bool - LoginPolicyPasswordReset bool - PasswordComplexityPolicy bool - LabelPolicyPrivateLabel bool - LabelPolicyWatermark bool - CustomDomain bool - PrivacyPolicy bool - MetadataUser bool - CustomTextMessage bool - CustomTextLogin bool - LockoutPolicy bool - ActionsAllowed domain.ActionsAllowed - MaxActions int -} - -func (wm *FeaturesWriteModel) Reduce() error { - for _, event := range wm.Events { - switch e := event.(type) { - case *features.FeaturesSetEvent: - if e.TierName != nil { - wm.TierName = *e.TierName - } - if e.TierDescription != nil { - wm.TierDescription = *e.TierDescription - } - wm.State = domain.FeaturesStateActive - if e.State != nil { - wm.State = *e.State - } - if e.StateDescription != nil { - wm.StateDescription = *e.StateDescription - } - if e.AuditLogRetention != nil { - wm.AuditLogRetention = *e.AuditLogRetention - } - if e.LoginPolicyFactors != nil { - wm.LoginPolicyFactors = *e.LoginPolicyFactors - } - if e.LoginPolicyIDP != nil { - wm.LoginPolicyIDP = *e.LoginPolicyIDP - } - if e.LoginPolicyPasswordless != nil { - wm.LoginPolicyPasswordless = *e.LoginPolicyPasswordless - } - if e.LoginPolicyRegistration != nil { - wm.LoginPolicyRegistration = *e.LoginPolicyRegistration - } - if e.LoginPolicyUsernameLogin != nil { - wm.LoginPolicyUsernameLogin = *e.LoginPolicyUsernameLogin - } - if e.LoginPolicyPasswordReset != nil { - wm.LoginPolicyPasswordReset = *e.LoginPolicyPasswordReset - } - if e.PasswordComplexityPolicy != nil { - wm.PasswordComplexityPolicy = *e.PasswordComplexityPolicy - } - if e.LabelPolicy != nil { - wm.LabelPolicyPrivateLabel = *e.LabelPolicy - } - if e.LabelPolicyPrivateLabel != nil { - wm.LabelPolicyPrivateLabel = *e.LabelPolicyPrivateLabel - } - if e.LabelPolicyWatermark != nil { - wm.LabelPolicyWatermark = *e.LabelPolicyWatermark - } - if e.CustomDomain != nil { - wm.CustomDomain = *e.CustomDomain - } - if e.PrivacyPolicy != nil { - wm.PrivacyPolicy = *e.PrivacyPolicy - } - if e.MetadataUser != nil { - wm.MetadataUser = *e.MetadataUser - } - if e.CustomTextMessage != nil { - wm.CustomTextMessage = *e.CustomTextMessage - } - if e.CustomTextLogin != nil { - wm.CustomTextLogin = *e.CustomTextLogin - } - if e.LockoutPolicy != nil { - wm.LockoutPolicy = *e.LockoutPolicy - } - if e.Actions != nil { - wm.ActionsAllowed = domain.ActionsNotAllowed - if *e.Actions { - wm.ActionsAllowed = domain.ActionsAllowedUnlimited - } - } - if e.ActionsAllowed != nil { - wm.ActionsAllowed = *e.ActionsAllowed - } - if e.MaxActions != nil { - wm.MaxActions = *e.MaxActions - } - case *features.FeaturesRemovedEvent: - wm.State = domain.FeaturesStateRemoved - } - } - return wm.WriteModel.Reduce() -} diff --git a/internal/command/instance.go b/internal/command/instance.go index ebe82c2d0..a1239bc6d 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -29,34 +29,10 @@ const ( ) type InstanceSetup struct { - zitadel ZitadelConfig - InstanceName string - CustomDomain string - Org OrgSetup - Features struct { - TierName string - TierDescription string - Retention time.Duration - State domain.FeaturesState - StateDescription string - LoginPolicyFactors bool - LoginPolicyIDP bool - LoginPolicyPasswordless bool - LoginPolicyRegistration bool - LoginPolicyUsernameLogin bool - LoginPolicyPasswordReset bool - PasswordComplexityPolicy bool - LabelPolicyPrivateLabel bool - LabelPolicyWatermark bool - CustomDomain bool - PrivacyPolicy bool - MetadataUser bool - CustomTextMessage bool - CustomTextLogin bool - LockoutPolicy bool - ActionsAllowed domain.ActionsAllowed - MaxActions int - } + zitadel ZitadelConfig + InstanceName string + CustomDomain string + Org OrgSetup SecretGenerators struct { PasswordSaltCost uint ClientSecret *crypto.GeneratorConfig @@ -191,31 +167,6 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str validations := []preparation.Validation{ addInstance(instanceAgg, setup.InstanceName), - SetDefaultFeatures( - instanceAgg, - setup.Features.TierName, - setup.Features.TierDescription, - setup.Features.State, - setup.Features.StateDescription, - setup.Features.Retention, - setup.Features.LoginPolicyFactors, - setup.Features.LoginPolicyIDP, - setup.Features.LoginPolicyPasswordless, - setup.Features.LoginPolicyRegistration, - setup.Features.LoginPolicyUsernameLogin, - setup.Features.LoginPolicyPasswordReset, - setup.Features.PasswordComplexityPolicy, - setup.Features.LabelPolicyPrivateLabel, - setup.Features.LabelPolicyWatermark, - setup.Features.CustomDomain, - setup.Features.PrivacyPolicy, - setup.Features.MetadataUser, - setup.Features.CustomTextMessage, - setup.Features.CustomTextLogin, - setup.Features.LockoutPolicy, - setup.Features.ActionsAllowed, - setup.Features.MaxActions, - ), addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeAppSecret, setup.SecretGenerators.ClientSecret), addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeInitCode, setup.SecretGenerators.InitializeUserCode), addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyEmailCode, setup.SecretGenerators.EmailVerificationCode), diff --git a/internal/command/instance_converter.go b/internal/command/instance_converter.go index 90c6e60dc..75320bdcb 100644 --- a/internal/command/instance_converter.go +++ b/internal/command/instance_converter.go @@ -169,31 +169,3 @@ func writeModelToIDPProvider(wm *IdentityProviderWriteModel) *domain.IDPProvider Type: wm.IDPProviderType, } } - -func writeModelToFeatures(wm *FeaturesWriteModel) *domain.Features { - return &domain.Features{ - ObjectRoot: writeModelToObjectRoot(wm.WriteModel), - TierName: wm.TierName, - TierDescription: wm.TierDescription, - State: wm.State, - StateDescription: wm.StateDescription, - AuditLogRetention: wm.AuditLogRetention, - LoginPolicyFactors: wm.LoginPolicyFactors, - LoginPolicyIDP: wm.LoginPolicyIDP, - LoginPolicyPasswordless: wm.LoginPolicyPasswordless, - LoginPolicyRegistration: wm.LoginPolicyRegistration, - LoginPolicyUsernameLogin: wm.LoginPolicyUsernameLogin, - LoginPolicyPasswordReset: wm.LoginPolicyPasswordReset, - PasswordComplexityPolicy: wm.PasswordComplexityPolicy, - LabelPolicyPrivateLabel: wm.LabelPolicyPrivateLabel, - LabelPolicyWatermark: wm.LabelPolicyWatermark, - CustomDomain: wm.CustomDomain, - PrivacyPolicy: wm.PrivacyPolicy, - MetadataUser: wm.MetadataUser, - CustomTextMessage: wm.CustomTextMessage, - CustomTextLogin: wm.CustomTextLogin, - LockoutPolicy: wm.LockoutPolicy, - ActionsAllowed: wm.ActionsAllowed, - MaxActions: wm.MaxActions, - } -} diff --git a/internal/command/instance_features.go b/internal/command/instance_features.go deleted file mode 100644 index a2ef29bca..000000000 --- a/internal/command/instance_features.go +++ /dev/null @@ -1,160 +0,0 @@ -package command - -import ( - "context" - "time" - - "github.com/zitadel/zitadel/internal/command/preparation" - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/instance" -) - -func SetDefaultFeatures( - a *instance.Aggregate, - tierName, - tierDescription string, - state domain.FeaturesState, - stateDescription string, - retention time.Duration, - loginPolicyFactors, - loginPolicyIDP, - loginPolicyPasswordless, - loginPolicyRegistration, - loginPolicyUsernameLogin, - loginPolicyPasswordReset, - passwordComplexityPolicy, - labelPolicyPrivateLabel, - labelPolicyWatermark, - customDomain, - privacyPolicy, - metadataUser, - customTextMessage, - customTextLogin, - lockoutPolicy bool, - actionsAllowed domain.ActionsAllowed, - maxActions int, -) preparation.Validation { - return func() (preparation.CreateCommands, error) { - if !state.Valid() || state == domain.FeaturesStateUnspecified || state == domain.FeaturesStateRemoved { - return nil, errors.ThrowInvalidArgument(nil, "INSTA-d3r1s", "Errors.Invalid.Argument") - } - return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { - writeModel, err := defaultFeatures(ctx, filter) - if err != nil { - return nil, err - } - event, hasChanged := writeModel.NewSetEvent(ctx, &a.Aggregate, - tierName, - tierDescription, - state, - stateDescription, - retention, - loginPolicyFactors, - loginPolicyIDP, - loginPolicyPasswordless, - loginPolicyRegistration, - loginPolicyUsernameLogin, - loginPolicyPasswordReset, - passwordComplexityPolicy, - labelPolicyPrivateLabel, - labelPolicyWatermark, - customDomain, - privacyPolicy, - metadataUser, - customTextMessage, - customTextLogin, - lockoutPolicy, - actionsAllowed, - maxActions, - ) - if !hasChanged { - return nil, errors.ThrowPreconditionFailed(nil, "INSTA-GE4h2", "Errors.Features.NotChanged") - } - return []eventstore.Command{ - event, - }, nil - }, nil - } -} - -func defaultFeatures(ctx context.Context, filter preparation.FilterToQueryReducer) (*InstanceFeaturesWriteModel, error) { - features := NewInstanceFeaturesWriteModel(ctx) - events, err := filter(ctx, features.Query()) - if err != nil { - return nil, err - } - if len(events) == 0 { - return features, nil - } - features.AppendEvents(events...) - err = features.Reduce() - return features, err -} - -func (c *Commands) SetDefaultFeatures(ctx context.Context, features *domain.Features) (*domain.ObjectDetails, error) { - existingFeatures := NewInstanceFeaturesWriteModel(ctx) - setEvent, err := c.setDefaultFeatures(ctx, existingFeatures, features) - if err != nil { - return nil, err - } - - pushedEvents, err := c.eventstore.Push(ctx, setEvent) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingFeatures, pushedEvents...) - if err != nil { - return nil, err - } - return writeModelToObjectDetails(&existingFeatures.WriteModel), nil -} - -func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *InstanceFeaturesWriteModel, features *domain.Features) (*instance.FeaturesSetEvent, error) { - err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures) - if err != nil { - return nil, err - } - setEvent, hasChanged := existingFeatures.NewSetEvent( - ctx, - InstanceAggregateFromWriteModel(&existingFeatures.FeaturesWriteModel.WriteModel), - features.TierName, - features.TierDescription, - features.State, - features.StateDescription, - features.AuditLogRetention, - features.LoginPolicyFactors, - features.LoginPolicyIDP, - features.LoginPolicyPasswordless, - features.LoginPolicyRegistration, - features.LoginPolicyUsernameLogin, - features.LoginPolicyPasswordReset, - features.PasswordComplexityPolicy, - features.LabelPolicyPrivateLabel, - features.LabelPolicyWatermark, - features.CustomDomain, - features.PrivacyPolicy, - features.MetadataUser, - features.CustomTextMessage, - features.CustomTextLogin, - features.LockoutPolicy, - features.ActionsAllowed, - features.MaxActions, - ) - if !hasChanged { - return nil, errors.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged") - } - return setEvent, nil -} - -func (c *Commands) getDefaultFeatures(ctx context.Context) (*domain.Features, error) { - existingFeatures := NewInstanceFeaturesWriteModel(ctx) - err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures) - if err != nil { - return nil, err - } - features := writeModelToFeatures(&existingFeatures.FeaturesWriteModel) - features.IsDefault = true - return features, nil -} diff --git a/internal/command/instance_features_model.go b/internal/command/instance_features_model.go deleted file mode 100644 index d91e4b743..000000000 --- a/internal/command/instance_features_model.go +++ /dev/null @@ -1,157 +0,0 @@ -package command - -import ( - "context" - "time" - - "github.com/zitadel/zitadel/internal/api/authz" - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/repository/instance" -) - -type InstanceFeaturesWriteModel struct { - FeaturesWriteModel -} - -func NewInstanceFeaturesWriteModel(ctx context.Context) *InstanceFeaturesWriteModel { - return &InstanceFeaturesWriteModel{ - FeaturesWriteModel{ - WriteModel: eventstore.WriteModel{ - AggregateID: authz.GetInstance(ctx).InstanceID(), - ResourceOwner: authz.GetInstance(ctx).InstanceID(), - }, - }, - } -} - -func (wm *InstanceFeaturesWriteModel) AppendEvents(events ...eventstore.Event) { - for _, event := range events { - switch e := event.(type) { - case *instance.FeaturesSetEvent: - wm.FeaturesWriteModel.AppendEvents(&e.FeaturesSetEvent) - } - } -} - -func (wm *InstanceFeaturesWriteModel) IsValid() bool { - return wm.AggregateID != "" -} - -func (wm *InstanceFeaturesWriteModel) Reduce() error { - return wm.FeaturesWriteModel.Reduce() -} - -func (wm *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder { - return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). - ResourceOwner(wm.ResourceOwner). - AddQuery(). - EventTypes(instance.FeaturesSetEventType). - AggregateTypes(instance.AggregateType). - Builder() -} - -func (wm *InstanceFeaturesWriteModel) NewSetEvent( - ctx context.Context, - aggregate *eventstore.Aggregate, - tierName, tierDescription string, - state domain.FeaturesState, - stateDescription string, - auditLogRetention time.Duration, - loginPolicyFactors, - loginPolicyIDP, - loginPolicyPasswordless, - loginPolicyRegistration, - loginPolicyUsernameLogin, - loginPolicyPasswordReset, - passwordComplexityPolicy, - labelPolicyPrivateLabel, - labelPolicyWatermark, - customDomain, - privacyPolicy, - metadataUser, - customTextMessage, - customTextLogin, - lockoutPolicy bool, - actionsAllowed domain.ActionsAllowed, - maxActions int, -) (*instance.FeaturesSetEvent, bool) { - - changes := make([]features.FeaturesChanges, 0) - - if tierName != "" && wm.TierName != tierName { - changes = append(changes, features.ChangeTierName(tierName)) - } - if wm.TierDescription != tierDescription { - changes = append(changes, features.ChangeTierDescription(tierDescription)) - } - if wm.State != state { - changes = append(changes, features.ChangeState(state)) - } - if wm.StateDescription != stateDescription { - changes = append(changes, features.ChangeStateDescription(stateDescription)) - } - if auditLogRetention != 0 && wm.AuditLogRetention != auditLogRetention { - changes = append(changes, features.ChangeAuditLogRetention(auditLogRetention)) - } - if wm.LoginPolicyFactors != loginPolicyFactors { - changes = append(changes, features.ChangeLoginPolicyFactors(loginPolicyFactors)) - } - if wm.LoginPolicyIDP != loginPolicyIDP { - changes = append(changes, features.ChangeLoginPolicyIDP(loginPolicyIDP)) - } - if wm.LoginPolicyPasswordless != loginPolicyPasswordless { - changes = append(changes, features.ChangeLoginPolicyPasswordless(loginPolicyPasswordless)) - } - if wm.LoginPolicyRegistration != loginPolicyRegistration { - changes = append(changes, features.ChangeLoginPolicyRegistration(loginPolicyRegistration)) - } - if wm.LoginPolicyUsernameLogin != loginPolicyUsernameLogin { - changes = append(changes, features.ChangeLoginPolicyUsernameLogin(loginPolicyUsernameLogin)) - } - if wm.LoginPolicyPasswordReset != loginPolicyPasswordReset { - changes = append(changes, features.ChangeLoginPolicyPasswordReset(loginPolicyPasswordReset)) - } - if wm.PasswordComplexityPolicy != passwordComplexityPolicy { - changes = append(changes, features.ChangePasswordComplexityPolicy(passwordComplexityPolicy)) - } - if wm.LabelPolicyPrivateLabel != labelPolicyPrivateLabel { - changes = append(changes, features.ChangeLabelPolicyPrivateLabel(labelPolicyPrivateLabel)) - } - if wm.LabelPolicyWatermark != labelPolicyWatermark { - changes = append(changes, features.ChangeLabelPolicyWatermark(labelPolicyWatermark)) - } - if wm.CustomDomain != customDomain { - changes = append(changes, features.ChangeCustomDomain(customDomain)) - } - if wm.PrivacyPolicy != privacyPolicy { - changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy)) - } - if wm.MetadataUser != metadataUser { - changes = append(changes, features.ChangeMetadataUser(metadataUser)) - } - if wm.CustomTextMessage != customTextMessage { - changes = append(changes, features.ChangeCustomTextMessage(customTextMessage)) - } - if wm.CustomTextLogin != customTextLogin { - changes = append(changes, features.ChangeCustomTextLogin(customTextLogin)) - } - if wm.LockoutPolicy != lockoutPolicy { - changes = append(changes, features.ChangeLockoutPolicy(lockoutPolicy)) - } - if wm.ActionsAllowed != actionsAllowed { - changes = append(changes, features.ChangeActionsAllowed(actionsAllowed)) - } - if wm.MaxActions != maxActions { - changes = append(changes, features.ChangeMaxActions(maxActions)) - } - if len(changes) == 0 { - return nil, false - } - changedEvent, err := instance.NewFeaturesSetEvent(ctx, aggregate, changes) - if err != nil { - return nil, false - } - return changedEvent, true -} diff --git a/internal/command/instance_features_test.go b/internal/command/instance_features_test.go deleted file mode 100644 index a86432583..000000000 --- a/internal/command/instance_features_test.go +++ /dev/null @@ -1,152 +0,0 @@ -package command - -import ( - "context" - "testing" - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/repository/instance" -) - -func TestSetDefaultFeatures(t *testing.T) { - type args struct { - a *instance.Aggregate - tierName string - tierDescription string - state domain.FeaturesState - stateDescription string - retention time.Duration - loginPolicyFactors bool - loginPolicyIDP bool - loginPolicyPasswordless bool - loginPolicyRegistration bool - loginPolicyUsernameLogin bool - loginPolicyPasswordReset bool - passwordComplexityPolicy bool - labelPolicyPrivateLabel bool - labelPolicyWatermark bool - customDomain bool - privacyPolicy bool - metadataUser bool - customTextMessage bool - customTextLogin bool - lockoutPolicy bool - actionsAllowed domain.ActionsAllowed - maxActions int - } - tests := []struct { - name string - args args - want Want - }{ - { - name: "invalid state", - args: args{ - a: instance.NewAggregate("INSTANCE"), - tierName: "", - tierDescription: "", - state: 0, - stateDescription: "", - retention: 0, - loginPolicyFactors: false, - loginPolicyIDP: false, - loginPolicyPasswordless: false, - loginPolicyRegistration: false, - loginPolicyUsernameLogin: false, - loginPolicyPasswordReset: false, - passwordComplexityPolicy: false, - labelPolicyPrivateLabel: false, - labelPolicyWatermark: false, - customDomain: false, - privacyPolicy: false, - metadataUser: false, - customTextMessage: false, - customTextLogin: false, - lockoutPolicy: false, - actionsAllowed: 0, - maxActions: 0, - }, - want: Want{ - ValidationErr: errors.ThrowInvalidArgument(nil, "INSTA-d3r1s", "Errors.Invalid.Argument"), - }, - }, - { - name: "correct", - args: args{ - a: instance.NewAggregate("INSTANCE"), - tierName: "", - tierDescription: "", - state: domain.FeaturesStateActive, - stateDescription: "", - retention: 0, - loginPolicyFactors: false, - loginPolicyIDP: false, - loginPolicyPasswordless: false, - loginPolicyRegistration: false, - loginPolicyUsernameLogin: false, - loginPolicyPasswordReset: false, - passwordComplexityPolicy: false, - labelPolicyPrivateLabel: false, - labelPolicyWatermark: false, - customDomain: false, - privacyPolicy: false, - metadataUser: false, - customTextMessage: false, - customTextLogin: false, - lockoutPolicy: false, - actionsAllowed: 0, - maxActions: 0, - }, - want: Want{ - Commands: []eventstore.Command{ - func() *instance.FeaturesSetEvent { - event, _ := instance.NewFeaturesSetEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, - []features.FeaturesChanges{ - features.ChangeState(domain.FeaturesStateActive), - }, - ) - return event - }(), - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - AssertValidation(t, SetDefaultFeatures( - tt.args.a, - tt.args.tierName, - tt.args.tierDescription, - tt.args.state, - tt.args.stateDescription, - tt.args.retention, - tt.args.loginPolicyFactors, - tt.args.loginPolicyIDP, - tt.args.loginPolicyPasswordless, - tt.args.loginPolicyRegistration, - tt.args.loginPolicyUsernameLogin, - tt.args.loginPolicyPasswordReset, - tt.args.passwordComplexityPolicy, - tt.args.labelPolicyPrivateLabel, - tt.args.labelPolicyWatermark, - tt.args.customDomain, - tt.args.privacyPolicy, - tt.args.metadataUser, - tt.args.customTextMessage, - tt.args.customTextLogin, - tt.args.lockoutPolicy, - tt.args.actionsAllowed, - tt.args.maxActions, - ), NewMultiFilter(). - Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { - return nil, nil - }). - Filter(), - tt.want) - }) - } -} diff --git a/internal/command/main_test.go b/internal/command/main_test.go index aa45f1c7d..06391db01 100644 --- a/internal/command/main_test.go +++ b/internal/command/main_test.go @@ -9,9 +9,7 @@ import ( "github.com/golang/mock/gomock" "golang.org/x/text/language" - "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/crypto" - "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/repository/mock" @@ -213,51 +211,6 @@ func GetMockSecretGenerator(t *testing.T) crypto.Generator { return generator } -func GetMockVerifier(t *testing.T, features ...string) *testVerifier { - return &testVerifier{ - features: features, - } -} - -type testVerifier struct { - features []string -} - -func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, string, error) { - return "userID", "agentID", "clientID", "de", "orgID", nil -} -func (v *testVerifier) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) { - return nil, nil -} - -func (v *testVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { - return "", nil, nil -} - -func (v *testVerifier) ExistsOrg(ctx context.Context, orgID string) error { - return nil -} - -func (v *testVerifier) VerifierClientID(ctx context.Context, appName string) (string, error) { - return "clientID", nil -} - -func (v *testVerifier) CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error { - for _, feature := range requiredFeatures { - hasFeature := false - for _, f := range v.features { - if f == feature { - hasFeature = true - break - } - } - if !hasFeature { - return errors.ThrowPermissionDenied(nil, "id", "missing feature") - } - } - return nil -} - type mockInstance struct{} func (m *mockInstance) InstanceID() string { diff --git a/internal/command/org_action.go b/internal/command/org_action.go index fe1971bba..aeeb5f587 100644 --- a/internal/command/org_action.go +++ b/internal/command/org_action.go @@ -15,10 +15,6 @@ func (c *Commands) AddAction(ctx context.Context, addAction *domain.Action, reso if !addAction.IsValid() { return "", nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-eg2gf", "Errors.Action.Invalid") } - err = c.checkAdditionalActionAllowed(ctx, resourceOwner) - if err != nil { - return "", nil, err - } addAction.AggregateID, err = c.idGenerator.Next() if err != nil { return "", nil, err @@ -44,27 +40,6 @@ func (c *Commands) AddAction(ctx context.Context, addAction *domain.Action, reso return actionModel.AggregateID, writeModelToObjectDetails(&actionModel.WriteModel), nil } -func (c *Commands) checkAdditionalActionAllowed(ctx context.Context, resourceOwner string) error { - features, err := c.getOrgFeaturesOrDefault(ctx, resourceOwner) - if err != nil { - return err - } - existingActions, err := c.getActionsByOrgWriteModelByID(ctx, resourceOwner) - if err != nil { - return err - } - activeActions := make([]*ActionWriteModel, 0, len(existingActions.Actions)) - for _, existingAction := range existingActions.Actions { - if existingAction.State == domain.ActionStateActive { - activeActions = append(activeActions, existingAction) - } - } - if features.ActionsAllowed == domain.ActionsAllowedUnlimited || len(activeActions) < features.MaxActions { - return nil - } - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dfwg2", "Errors.Action.MaxAllowed") -} - func (c *Commands) ChangeAction(ctx context.Context, actionChange *domain.Action, resourceOwner string) (*domain.ObjectDetails, error) { if !actionChange.IsValid() || actionChange.AggregateID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Df2f3", "Errors.Action.Invalid") @@ -145,10 +120,6 @@ func (c *Commands) ReactivateAction(ctx context.Context, actionID string, resour if existingAction.State != domain.ActionStateInactive { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-J53zh", "Errors.Action.NotInactive") } - err = c.checkAdditionalActionAllowed(ctx, resourceOwner) - if err != nil { - return nil, err - } actionAgg := ActionAggregateFromWriteModel(&existingAction.WriteModel) events := []eventstore.Command{ diff --git a/internal/command/org_action_test.go b/internal/command/org_action_test.go index 350ae0078..dadb64261 100644 --- a/internal/command/org_action_test.go +++ b/internal/command/org_action_test.go @@ -6,8 +6,6 @@ import ( "github.com/stretchr/testify/assert" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" @@ -56,76 +54,10 @@ func TestCommands_AddAction(t *testing.T) { err: errors.IsErrorInvalidArgument, }, }, - { - "no additional allowed, error", - fields{ - eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - func() eventstore.Command { - e, _ := org.NewFeaturesSetEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - []features.FeaturesChanges{ - features.ChangeMaxActions(1), - }, - ) - return e - }(), - ), - ), - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - "name", - "name() {};", - 0, - false, - ), - ), - ), - ), - }, - args{ - ctx: context.Background(), - addAction: &domain.Action{ - Name: "name", - Script: "name() {};", - }, - resourceOwner: "org1", - }, - res{ - err: errors.IsPreconditionFailed, - }, - }, { "unique constraint failed, error", fields{ eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - func() eventstore.Command { - e, _ := org.NewFeaturesSetEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - []features.FeaturesChanges{ - features.ChangeMaxActions(2), - }, - ) - return e - }(), - ), - ), - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - "name", - "name() {};", - 0, - false, - ), - ), - ), expectPushFailed( errors.ThrowPreconditionFailed(nil, "id", "name already exists"), []*repository.Event{ @@ -160,30 +92,6 @@ func TestCommands_AddAction(t *testing.T) { "push ok", fields{ eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - func() eventstore.Command { - e, _ := org.NewFeaturesSetEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - []features.FeaturesChanges{ - features.ChangeMaxActions(2), - }, - ) - return e - }(), - ), - ), - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - "name", - "name() {};", - 0, - false, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -663,94 +571,10 @@ func TestCommands_ReactivateAction(t *testing.T) { err: errors.IsPreconditionFailed, }, }, - { - "no additional allowed, error", - fields{ - eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - "name", - "name() {};", - 0, - false, - ), - ), - eventFromEventPusher( - action.NewDeactivatedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - ), - ), - ), - expectFilter( - eventFromEventPusher( - func() eventstore.Command { - e, _ := org.NewFeaturesSetEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - []features.FeaturesChanges{ - features.ChangeMaxActions(1), - }, - ) - return e - }(), - ), - ), - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id2", "org1").Aggregate, - "name2", - "name2() {};", - 0, - false, - ), - ), - ), - ), - }, - args{ - ctx: context.Background(), - actionID: "id1", - resourceOwner: "org1", - }, - res{ - err: errors.IsPreconditionFailed, - }, - }, { "reactivate ok", fields{ eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - action.NewAddedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - "name", - "name() {};", - 0, - false, - ), - ), - eventFromEventPusher( - action.NewDeactivatedEvent(context.Background(), - &action.NewAggregate("id1", "org1").Aggregate, - ), - ), - ), - expectFilter( - eventFromEventPusher( - func() eventstore.Command { - e, _ := org.NewFeaturesSetEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - []features.FeaturesChanges{ - features.ChangeMaxActions(1), - }, - ) - return e - }(), - ), - ), expectFilter( eventFromEventPusher( action.NewAddedEvent(context.Background(), diff --git a/internal/command/org_features.go b/internal/command/org_features.go deleted file mode 100644 index bbc4a0551..000000000 --- a/internal/command/org_features.go +++ /dev/null @@ -1,393 +0,0 @@ -package command - -import ( - "context" - - "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/org" -) - -func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, features *domain.Features) (*domain.ObjectDetails, error) { - if resourceOwner == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "Features-G5tg", "Errors.ResourceOwnerMissing") - } - err := c.checkOrgExists(ctx, resourceOwner) - if err != nil { - return nil, err - } - existingFeatures := NewOrgFeaturesWriteModel(resourceOwner) - err = c.eventstore.FilterToQueryReducer(ctx, existingFeatures) - if err != nil { - return nil, err - } - setEvent, hasChanged := existingFeatures.NewSetEvent( - ctx, - OrgAggregateFromWriteModel(&existingFeatures.FeaturesWriteModel.WriteModel), - features.TierName, - features.TierDescription, - features.State, - features.StateDescription, - features.AuditLogRetention, - features.LoginPolicyFactors, - features.LoginPolicyIDP, - features.LoginPolicyPasswordless, - features.LoginPolicyRegistration, - features.LoginPolicyUsernameLogin, - features.LoginPolicyPasswordReset, - features.PasswordComplexityPolicy, - features.LabelPolicyPrivateLabel, - features.LabelPolicyWatermark, - features.CustomDomain, - features.PrivacyPolicy, - features.MetadataUser, - features.CustomTextMessage, - features.CustomTextLogin, - features.LockoutPolicy, - features.ActionsAllowed, - features.MaxActions, - ) - if !hasChanged { - return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged") - } - - events, err := c.ensureOrgSettingsToFeatures(ctx, resourceOwner, features) - if err != nil { - return nil, err - } - events = append(events, setEvent) - - pushedEvents, err := c.eventstore.Push(ctx, events...) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingFeatures, pushedEvents...) - if err != nil { - return nil, err - } - return writeModelToObjectDetails(&existingFeatures.WriteModel), nil -} - -func (c *Commands) RemoveOrgFeatures(ctx context.Context, orgID string) (*domain.ObjectDetails, error) { - if orgID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "Features-G5tg", "Errors.ResourceOwnerMissing") - } - existingFeatures := NewOrgFeaturesWriteModel(orgID) - err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures) - if err != nil { - return nil, err - } - if existingFeatures.State == domain.FeaturesStateUnspecified || existingFeatures.State == domain.FeaturesStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "Features-Bg32G", "Errors.Features.NotFound") - } - removedEvent := org.NewFeaturesRemovedEvent(ctx, OrgAggregateFromWriteModel(&existingFeatures.FeaturesWriteModel.WriteModel)) - - features, err := c.getDefaultFeatures(ctx) - if err != nil { - return nil, err - } - events, err := c.ensureOrgSettingsToFeatures(ctx, orgID, features) - if err != nil { - return nil, err - } - - events = append(events, removedEvent) - pushedEvents, err := c.eventstore.Push(ctx, events...) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingFeatures, pushedEvents...) - if err != nil { - return nil, err - } - return writeModelToObjectDetails(&existingFeatures.WriteModel), nil -} - -func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.Command, error) { - events, err := c.setAllowedLoginPolicy(ctx, orgID, features) - if err != nil { - return nil, err - } - if !features.PasswordComplexityPolicy { - removePasswordComplexityEvent, err := c.removePasswordComplexityPolicyIfExists(ctx, orgID) - if err != nil { - return nil, err - } - if removePasswordComplexityEvent != nil { - events = append(events, removePasswordComplexityEvent) - } - } - labelPolicyEvents, err := c.setAllowedLabelPolicy(ctx, orgID, features) - if err != nil { - return nil, err - } - events = append(events, labelPolicyEvents...) - - if !features.CustomDomain { - removeCustomDomainsEvents, err := c.removeCustomDomains(ctx, orgID) - if err != nil { - return nil, err - } - if removeCustomDomainsEvents != nil { - events = append(events, removeCustomDomainsEvents...) - } - } - if !features.CustomTextMessage { - removeCustomMessageTextEvents, err := c.removeOrgMessageTextsIfExists(ctx, orgID) - if err != nil { - return nil, err - } - if removeCustomMessageTextEvents != nil { - events = append(events, removeCustomMessageTextEvents...) - } - } - if !features.CustomTextLogin { - removeCustomLoginTextEvents, err := c.removeOrgLoginTextsIfExists(ctx, orgID) - if err != nil { - return nil, err - } - if removeCustomLoginTextEvents != nil { - events = append(events, removeCustomLoginTextEvents...) - } - } - if !features.PrivacyPolicy { - removePrivacyPolicyEvent, err := c.removePrivacyPolicyIfExists(ctx, orgID) - if err != nil { - return nil, err - } - if removePrivacyPolicyEvent != nil { - events = append(events, removePrivacyPolicyEvent) - } - } - if !features.LockoutPolicy { - removeLockoutPolicyEvent, err := c.removeLockoutPolicyIfExists(ctx, orgID) - if err != nil { - return nil, err - } - if removeLockoutPolicyEvent != nil { - events = append(events, removeLockoutPolicyEvent) - } - } - if !features.MetadataUser { - removeOrgUserMetadatas, err := c.removeUserMetadataFromOrg(ctx, orgID) - if err != nil { - return nil, err - } - if len(removeOrgUserMetadatas) > 0 { - events = append(events, removeOrgUserMetadatas...) - } - } - if features.ActionsAllowed == domain.ActionsNotAllowed { - removeOrgActions, err := c.removeActionsFromOrg(ctx, orgID) - if err != nil { - return nil, err - } - if len(removeOrgActions) > 0 { - events = append(events, removeOrgActions...) - } - } - if features.ActionsAllowed == domain.ActionsMaxAllowed { - deactivateActions, err := c.deactivateNotAllowedActionsFromOrg(ctx, orgID, features.MaxActions) - if err != nil { - return nil, err - } - if len(deactivateActions) > 0 { - events = append(events, deactivateActions...) - } - } - return events, nil -} - -func (c *Commands) setAllowedLoginPolicy(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.Command, error) { - events := make([]eventstore.Command, 0) - existingPolicy, err := c.orgLoginPolicyWriteModelByID(ctx, orgID) - if err != nil { - return nil, err - } - if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { - return nil, nil - } - defaultPolicy, err := c.getDefaultLoginPolicy(ctx) - if err != nil { - return nil, err - } - policy := *existingPolicy - if !features.LoginPolicyFactors { - if defaultPolicy.ForceMFA != existingPolicy.ForceMFA { - policy.ForceMFA = defaultPolicy.ForceMFA - } - authFactorsEvents, err := c.setDefaultAuthFactorsInCustomLoginPolicy(ctx, orgID) - if err != nil { - return nil, err - } - events = append(events, authFactorsEvents...) - } - if !features.LoginPolicyIDP { - if defaultPolicy.AllowExternalIDP != existingPolicy.AllowExternalIDP { - policy.AllowExternalIDP = defaultPolicy.AllowExternalIDP - } - //TODO: handle idps - } - if !features.LoginPolicyRegistration && defaultPolicy.AllowRegister != existingPolicy.AllowRegister { - policy.AllowRegister = defaultPolicy.AllowRegister - } - if !features.LoginPolicyPasswordless && defaultPolicy.PasswordlessType != existingPolicy.PasswordlessType { - policy.PasswordlessType = defaultPolicy.PasswordlessType - } - if !features.LoginPolicyUsernameLogin && defaultPolicy.AllowUsernamePassword != existingPolicy.AllowUserNamePassword { - policy.AllowUserNamePassword = defaultPolicy.AllowUsernamePassword - } - if !features.LoginPolicyPasswordReset && defaultPolicy.HidePasswordReset != existingPolicy.HidePasswordReset { - policy.HidePasswordReset = defaultPolicy.HidePasswordReset - } - changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, - OrgAggregateFromWriteModel(&existingPolicy.WriteModel), - policy.AllowUserNamePassword, - policy.AllowRegister, - policy.AllowExternalIDP, - policy.ForceMFA, - policy.HidePasswordReset, - policy.PasswordlessType, - policy.PasswordCheckLifetime, - policy.ExternalLoginCheckLifetime, - policy.MFAInitSkipLifetime, - policy.SecondFactorCheckLifetime, - policy.MultiFactorCheckLifetime) - if hasChanged { - events = append(events, changedEvent) - } - return events, nil -} - -func (c *Commands) setDefaultAuthFactorsInCustomLoginPolicy(ctx context.Context, orgID string) ([]eventstore.Command, error) { - orgAuthFactors, err := c.orgLoginPolicyAuthFactorsWriteModel(ctx, orgID) - if err != nil { - return nil, err - } - events := make([]eventstore.Command, 0) - for _, factor := range domain.SecondFactorTypes() { - state := orgAuthFactors.SecondFactors[factor] - if state == nil || state.IAM == state.Org { - continue - } - secondFactorWriteModel := orgAuthFactors.ToSecondFactorWriteModel(factor) - if state.IAM == domain.FactorStateActive { - event, err := c.addSecondFactorToLoginPolicy(ctx, secondFactorWriteModel, factor) - if err != nil { - return nil, err - } - if event != nil { - events = append(events, event) - } - continue - } - event, err := c.removeSecondFactorFromLoginPolicy(ctx, secondFactorWriteModel, factor) - if err != nil { - return nil, err - } - if event != nil { - events = append(events, event) - } - } - - for _, factor := range domain.MultiFactorTypes() { - state := orgAuthFactors.MultiFactors[factor] - if state == nil || state.IAM == state.Org { - continue - } - multiFactorWriteModel := orgAuthFactors.ToMultiFactorWriteModel(factor) - if state.IAM == domain.FactorStateActive { - event, err := c.addMultiFactorToLoginPolicy(ctx, multiFactorWriteModel, factor) - if err != nil { - return nil, err - } - if event != nil { - events = append(events, event) - } - continue - } - event, err := c.removeMultiFactorFromLoginPolicy(ctx, multiFactorWriteModel, factor) - if err != nil { - return nil, err - } - if event != nil { - events = append(events, event) - } - } - return events, nil -} - -func (c *Commands) setAllowedLabelPolicy(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.Command, error) { - events := make([]eventstore.Command, 0) - existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID) - if err != nil { - return nil, err - } - if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { - return nil, nil - } - if !features.LabelPolicyPrivateLabel && !features.LabelPolicyWatermark { - removeEvent, err := c.removeLabelPolicy(ctx, existingPolicy) - if err != nil { - return nil, err - } - return append(events, removeEvent), nil - } - defaultPolicy, err := c.getDefaultLabelPolicy(ctx) - if err != nil { - return nil, err - } - policy := *existingPolicy - if !features.LabelPolicyWatermark && defaultPolicy.DisableWatermark != existingPolicy.DisableWatermark { - policy.DisableWatermark = defaultPolicy.DisableWatermark - } - if !features.LabelPolicyPrivateLabel { - if defaultPolicy.HideLoginNameSuffix != existingPolicy.HideLoginNameSuffix { - policy.HideLoginNameSuffix = defaultPolicy.HideLoginNameSuffix - } - policy.PrimaryColor = "" - policy.BackgroundColor = "" - policy.WarnColor = "" - policy.FontColor = "" - policy.PrimaryColorDark = "" - policy.BackgroundColorDark = "" - policy.WarnColorDark = "" - policy.FontColorDark = "" - - assetsEvent, err := c.removeLabelPolicyAssets(ctx, existingPolicy) - if err != nil { - return nil, err - } - events = append(events, assetsEvent) - } - changedEvent, hasChangedEvent := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), - policy.PrimaryColor, policy.BackgroundColor, policy.WarnColor, policy.FontColor, - policy.PrimaryColorDark, policy.BackgroundColorDark, policy.WarnColorDark, policy.FontColorDark, - policy.HideLoginNameSuffix, policy.ErrorMsgPopup, policy.HideLoginNameSuffix) - if hasChangedEvent { - events = append(events, changedEvent) - } - if len(events) > 0 { - events = append(events, org.NewLabelPolicyActivatedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel))) - } - return events, nil -} - -func (c *Commands) getOrgFeaturesOrDefault(ctx context.Context, orgID string) (*domain.Features, error) { - existingFeatures := NewOrgFeaturesWriteModel(orgID) - err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures) - if err != nil { - return nil, err - } - if existingFeatures.State != domain.FeaturesStateUnspecified && existingFeatures.State != domain.FeaturesStateRemoved { - return writeModelToFeatures(&existingFeatures.FeaturesWriteModel), nil - } - - existingIAMFeatures := NewInstanceFeaturesWriteModel(ctx) - err = c.eventstore.FilterToQueryReducer(ctx, existingIAMFeatures) - if err != nil { - return nil, err - } - return writeModelToFeatures(&existingIAMFeatures.FeaturesWriteModel), nil -} diff --git a/internal/command/org_features_model.go b/internal/command/org_features_model.go deleted file mode 100644 index 0b6e0b7db..000000000 --- a/internal/command/org_features_model.go +++ /dev/null @@ -1,163 +0,0 @@ -package command - -import ( - "context" - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/repository/org" -) - -type OrgFeaturesWriteModel struct { - FeaturesWriteModel -} - -func NewOrgFeaturesWriteModel(orgID string) *OrgFeaturesWriteModel { - return &OrgFeaturesWriteModel{ - FeaturesWriteModel{ - WriteModel: eventstore.WriteModel{ - AggregateID: orgID, - ResourceOwner: orgID, - }, - }, - } -} - -func (wm *OrgFeaturesWriteModel) AppendEvents(events ...eventstore.Event) { - for _, event := range events { - switch e := event.(type) { - case *org.FeaturesSetEvent: - wm.FeaturesWriteModel.AppendEvents(&e.FeaturesSetEvent) - case *org.FeaturesRemovedEvent: - wm.FeaturesWriteModel.AppendEvents(&e.FeaturesRemovedEvent) - } - } -} - -func (wm *OrgFeaturesWriteModel) IsValid() bool { - return wm.AggregateID != "" -} - -func (wm *OrgFeaturesWriteModel) Reduce() error { - return wm.FeaturesWriteModel.Reduce() -} - -func (wm *OrgFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder { - return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). - ResourceOwner(wm.ResourceOwner). - AddQuery(). - AggregateTypes(org.AggregateType). - AggregateIDs(wm.FeaturesWriteModel.AggregateID). - EventTypes( - org.FeaturesSetEventType, - org.FeaturesRemovedEventType). - Builder() -} - -func (wm *OrgFeaturesWriteModel) NewSetEvent( - ctx context.Context, - aggregate *eventstore.Aggregate, - tierName, - tierDescription string, - state domain.FeaturesState, - stateDescription string, - auditLogRetention time.Duration, - loginPolicyFactors, - loginPolicyIDP, - loginPolicyPasswordless, - loginPolicyRegistration, - loginPolicyUsernameLogin, - loginPolicyPasswordReset, - passwordComplexityPolicy, - labelPolicyPrivateLabel, - labelPolicyWatermark, - customDomain, - privacyPolicy, - metadataUser, - customTextMessage, - customTextLogin, - lockoutPolicy bool, - actionsAllowed domain.ActionsAllowed, - maxActions int, -) (*org.FeaturesSetEvent, bool) { - - changes := make([]features.FeaturesChanges, 0) - - if tierName != "" && wm.TierName != tierName { - changes = append(changes, features.ChangeTierName(tierName)) - } - if wm.TierDescription != tierDescription { - changes = append(changes, features.ChangeTierDescription(tierDescription)) - } - if wm.State != state { - changes = append(changes, features.ChangeState(state)) - } - if stateDescription != "" && wm.StateDescription != stateDescription { - changes = append(changes, features.ChangeStateDescription(stateDescription)) - } - if auditLogRetention != 0 && wm.AuditLogRetention != auditLogRetention { - changes = append(changes, features.ChangeAuditLogRetention(auditLogRetention)) - } - if wm.LoginPolicyFactors != loginPolicyFactors { - changes = append(changes, features.ChangeLoginPolicyFactors(loginPolicyFactors)) - } - if wm.LoginPolicyIDP != loginPolicyIDP { - changes = append(changes, features.ChangeLoginPolicyIDP(loginPolicyIDP)) - } - if wm.LoginPolicyPasswordless != loginPolicyPasswordless { - changes = append(changes, features.ChangeLoginPolicyPasswordless(loginPolicyPasswordless)) - } - if wm.LoginPolicyRegistration != loginPolicyRegistration { - changes = append(changes, features.ChangeLoginPolicyRegistration(loginPolicyRegistration)) - } - if wm.LoginPolicyUsernameLogin != loginPolicyUsernameLogin { - changes = append(changes, features.ChangeLoginPolicyUsernameLogin(loginPolicyUsernameLogin)) - } - if wm.LoginPolicyPasswordReset != loginPolicyPasswordReset { - changes = append(changes, features.ChangeLoginPolicyPasswordReset(loginPolicyPasswordReset)) - } - if wm.PasswordComplexityPolicy != passwordComplexityPolicy { - changes = append(changes, features.ChangePasswordComplexityPolicy(passwordComplexityPolicy)) - } - if wm.LabelPolicyPrivateLabel != labelPolicyPrivateLabel { - changes = append(changes, features.ChangeLabelPolicyPrivateLabel(labelPolicyPrivateLabel)) - } - if wm.LabelPolicyWatermark != labelPolicyWatermark { - changes = append(changes, features.ChangeLabelPolicyWatermark(labelPolicyWatermark)) - } - if wm.CustomDomain != customDomain { - changes = append(changes, features.ChangeCustomDomain(customDomain)) - } - if wm.PrivacyPolicy != privacyPolicy { - changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy)) - } - if wm.MetadataUser != metadataUser { - changes = append(changes, features.ChangeMetadataUser(metadataUser)) - } - if wm.CustomTextMessage != customTextMessage { - changes = append(changes, features.ChangeCustomTextMessage(customTextMessage)) - } - if wm.CustomTextLogin != customTextLogin { - changes = append(changes, features.ChangeCustomTextLogin(customTextLogin)) - } - if wm.LockoutPolicy != lockoutPolicy { - changes = append(changes, features.ChangeLockoutPolicy(lockoutPolicy)) - } - if wm.ActionsAllowed != actionsAllowed { - changes = append(changes, features.ChangeActionsAllowed(actionsAllowed)) - } - if wm.MaxActions != maxActions { - changes = append(changes, features.ChangeMaxActions(maxActions)) - } - - if len(changes) == 0 { - return nil, false - } - changedEvent, err := org.NewFeaturesSetEvent(ctx, aggregate, changes) - if err != nil { - return nil, false - } - return changedEvent, true -} diff --git a/internal/command/org_features_test.go b/internal/command/org_features_test.go deleted file mode 100644 index 4aaccf098..000000000 --- a/internal/command/org_features_test.go +++ /dev/null @@ -1,1764 +0,0 @@ -package command - -import ( - "context" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "golang.org/x/text/language" - - "github.com/zitadel/zitadel/internal/api/authz" - "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/repository" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/repository/user" - "github.com/zitadel/zitadel/internal/static" - "github.com/zitadel/zitadel/internal/static/mock" -) - -func TestCommandSide_SetOrgFeatures(t *testing.T) { - type fields struct { - eventstore *eventstore.Eventstore - static static.Storage - } - type args struct { - ctx context.Context - resourceOwner string - features *domain.Features - } - type res struct { - want *domain.ObjectDetails - err func(error) bool - } - tests := []struct { - name string - fields fields - args args - res res - }{ - { - name: "resourceowner missing, error", - fields: fields{ - eventstore: eventstoreExpect( - t, - ), - }, - args: args{ - ctx: context.Background(), - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - }, - }, - res: res{ - err: caos_errs.IsErrorInvalidArgument, - }, - }, - { - name: "no change, error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - ), - ), - }, - args: args{ - ctx: context.Background(), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - }, - }, - res: res{ - err: caos_errs.IsPreconditionFailed, - }, - }, - { - name: "org does not exist, error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter(), - ), - }, - args: args{ - ctx: context.Background(), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - }, - }, - res: res{ - err: caos_errs.IsPreconditionFailed, - }, - }, - { - name: "set with default policies, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helpLink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - CustomTextMessage: false, - CustomTextLogin: false, - PrivacyPolicy: false, - MetadataUser: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - { - name: "set with default policies, custom domains, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test2", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test1", true), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test2", false), - ), - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - uniqueConstraintsFromEventConstraint(org.NewRemoveOrgDomainUniqueConstraint("test1")), - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - PrivacyPolicy: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - { - name: "set with default policies, custom domains, default not primary, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test2", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - org.NewDomainPrimarySetEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "org1.iam-domain"), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test1", true), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test2", false), - ), - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - uniqueConstraintsFromEventConstraint(org.NewRemoveOrgDomainUniqueConstraint("test1")), - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - PrivacyPolicy: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - { - name: "set with default policies, custom domains, default not existing, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "test2", - ), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", true, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - org.NewDomainAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "org1.iam-domain"), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "org1.iam-domain"), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test1", true), - ), - eventFromEventPusher( - org.NewDomainRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "test2", false), - ), - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - uniqueConstraintsFromEventConstraint(org.NewRemoveOrgDomainUniqueConstraint("test1")), - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - PrivacyPolicy: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - { - name: "set with custom policies, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - //checkOrgExists - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - //NewOrgFeaturesWriteModel - expectFilter(), - //begin ensureOrgSettingsToFeatures - //begin setAllowedLoginPolicy - //orgLoginPolicyWriteModelByID - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - true, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - eventFromEventPusher( - org.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeNotAllowed, - time.Hour*10, - time.Hour*20, - time.Hour*30, - time.Hour*40, - time.Hour*50, - ), - ), - ), - //getDefaultLoginPolicy - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - true, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - //begin setDefaultAuthFactorsInCustomLoginPolicy - //orgLoginPolicyAuthFactorsWriteModel - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicySecondFactorAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, domain.SecondFactorTypeU2F), - ), - eventFromEventPusher( - instance.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, domain.MultiFactorTypeU2FWithPIN), - ), - eventFromEventPusher( - org.NewLoginPolicySecondFactorAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.SecondFactorTypeOTP), - ), - ), - //addSecondFactorToLoginPolicy - expectFilter(), - //removeSecondFactorFromLoginPolicy - expectFilter(), - //addMultiFactorToLoginPolicy - expectFilter(), - //end setDefaultAuthFactorsInCustomLoginPolicy - //orgPasswordComplexityPolicyWriteModelByID - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - eventFromEventPusher( - org.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 7, - false, - false, - false, - false, - ), - ), - ), - //begin setDefaultAuthFactorsInCustomLoginPolicy - //orgLabelPolicyWriteModelByID - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - eventFromEventPusher( - org.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "custom", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - //removeLabelPolicy - expectFilter(), - //end setDefaultAuthFactorsInCustomLoginPolicy - //removeCustomDomains - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewLockoutPolicyAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - org.NewLoginPolicySecondFactorRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.SecondFactorTypeOTP), - ), - eventFromEventPusher( - org.NewLoginPolicySecondFactorAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.SecondFactorTypeU2F), - ), - eventFromEventPusher( - org.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.MultiFactorTypeU2FWithPIN), - ), - eventFromEventPusher( - newLoginPolicyChangedEvent(context.Background(), "org1", - true, true, true, true, true, domain.PasswordlessTypeAllowed, - nil, - nil, - nil, - nil, - nil), - ), - eventFromEventPusher( - org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate), - ), - eventFromEventPusher( - org.NewLabelPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate), - ), - eventFromEventPusher( - org.NewCustomTextTemplateRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.InitCodeMessageType, language.English), - ), - eventFromEventPusher( - org.NewCustomTextTemplateRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.LoginCustomText, language.English), - ), - eventFromEventPusher( - org.NewPrivacyPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate), - ), - eventFromEventPusher( - org.NewLockoutPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate), - ), - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - ), - ), - static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectsNoError(), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - MetadataUser: false, - PrivacyPolicy: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - { - name: "set with default policies, usermetadata, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - ), - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - user.NewMetadataSetEvent( - context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - "key", - []byte("value"), - ), - ), - ), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - user.NewMetadataRemovedAllEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate), - ), - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour), - ), - }, - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - features: &domain.Features{ - TierName: "Test", - State: domain.FeaturesStateActive, - AuditLogRetention: time.Hour, - LoginPolicyFactors: false, - LoginPolicyIDP: false, - LoginPolicyPasswordless: false, - LoginPolicyRegistration: false, - LoginPolicyUsernameLogin: false, - LoginPolicyPasswordReset: false, - PasswordComplexityPolicy: false, - LabelPolicyPrivateLabel: false, - LabelPolicyWatermark: false, - CustomDomain: false, - CustomTextMessage: false, - CustomTextLogin: false, - PrivacyPolicy: false, - MetadataUser: false, - LockoutPolicy: false, - ActionsAllowed: domain.ActionsNotAllowed, - }, - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &Commands{ - eventstore: tt.fields.eventstore, - static: tt.fields.static, - } - got, err := r.SetOrgFeatures(tt.args.ctx, tt.args.resourceOwner, tt.args.features) - if tt.res.err == nil { - assert.NoError(t, err) - } - if tt.res.err != nil && !tt.res.err(err) { - t.Errorf("got wrong err: %v ", err) - } - if tt.res.err == nil { - assert.Equal(t, tt.res.want, got) - } - }) - } -} - -func TestCommandSide_RemoveOrgFeatures(t *testing.T) { - type fields struct { - eventstore *eventstore.Eventstore - } - type args struct { - ctx context.Context - resourceOwner string - } - type res struct { - want *domain.ObjectDetails - err func(error) bool - } - tests := []struct { - name string - fields fields - args args - res res - }{ - { - name: "resourceowner missing, error", - fields: fields{ - eventstore: eventstoreExpect( - t, - ), - }, - args: args{ - ctx: context.Background(), - }, - res: res{ - err: caos_errs.IsErrorInvalidArgument, - }, - }, - { - name: "no features set, error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter(), - ), - }, - args: args{ - ctx: context.Background(), - resourceOwner: "org1", - }, - res: res{ - err: caos_errs.IsNotFound, - }, - }, - { - name: "remove with default policies, ok", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour)), - ), - expectFilter( - eventFromEventPusher( - newIAMFeaturesSetEvent(context.Background(), "Default", domain.FeaturesStateActive, time.Hour)), - ), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPasswordComplexityPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 8, - false, - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "primary", - "secondary", - "warn", - "font", - "primary-dark", - "secondary-dark", - "warn-dark", - "font-dark", - false, - false, - false, - ), - ), - ), - expectFilter( - eventFromEventPusher( - org.NewOrgAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1", - ), - ), - eventFromEventPusher( - org.NewDomainAddedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainVerifiedEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - eventFromEventPusher( - org.NewDomainPrimarySetEvent( - context.Background(), - &org.NewAggregate("org1").Aggregate, - "org1.iam-domain", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.InitCodeMessageType, - domain.MessageSubject, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewCustomTextSetEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - domain.LoginCustomText, - domain.LoginKeyExternalRegistrationUserOverviewTitle, - "text", - language.English, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewPrivacyPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "toslink", - "privacylink", - "helplink", - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLockoutPolicyAddedEvent( - context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - 5, - false, - ), - ), - ), - expectFilter(), - expectFilter(), - expectPush( - []*repository.Event{ - eventFromEventPusher( - org.NewFeaturesRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate), - ), - }, - ), - ), - }, - args: args{ - ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), - resourceOwner: "org1", - }, - res: res{ - want: &domain.ObjectDetails{ - ResourceOwner: "org1", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &Commands{ - eventstore: tt.fields.eventstore, - } - got, err := r.RemoveOrgFeatures(tt.args.ctx, tt.args.resourceOwner) - if tt.res.err == nil { - assert.NoError(t, err) - } - if tt.res.err != nil && !tt.res.err(err) { - t.Errorf("got wrong err: %v ", err) - } - if tt.res.err == nil { - assert.Equal(t, tt.res.want, got) - } - }) - } -} - -func newIAMFeaturesSetEvent(ctx context.Context, tierName string, state domain.FeaturesState, auditLog time.Duration) *instance.FeaturesSetEvent { - event, _ := instance.NewFeaturesSetEvent( - ctx, - &instance.NewAggregate("INSTANCE").Aggregate, - []features.FeaturesChanges{ - features.ChangeTierName(tierName), - features.ChangeState(state), - features.ChangeAuditLogRetention(auditLog), - }, - ) - return event -} - -func newFeaturesSetEvent(ctx context.Context, orgID string, tierName string, state domain.FeaturesState, auditLog time.Duration) *org.FeaturesSetEvent { - event, _ := org.NewFeaturesSetEvent( - ctx, - &org.NewAggregate(orgID).Aggregate, - []features.FeaturesChanges{ - features.ChangeTierName(tierName), - features.ChangeState(state), - features.ChangeAuditLogRetention(auditLog), - }, - ) - return event -} diff --git a/internal/command/org_policy_label.go b/internal/command/org_policy_label.go index 5663eabf2..83387e043 100644 --- a/internal/command/org_policy_label.go +++ b/internal/command/org_policy_label.go @@ -25,10 +25,6 @@ func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, pol return nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LabelPolicy.AlreadyExists") } - err = c.checkLabelPolicyAllowed(ctx, resourceOwner, policy) - if err != nil { - return nil, err - } orgAgg := OrgAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyAddedEvent( ctx, @@ -70,11 +66,6 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string, return nil, caos_errs.ThrowNotFound(nil, "Org-0K9dq", "Errors.Org.LabelPolicy.NotFound") } - err = c.checkLabelPolicyAllowed(ctx, resourceOwner, policy) - if err != nil { - return nil, err - } - orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel) changedEvent, hasChanged := existingPolicy.NewChangedEvent( ctx, @@ -105,28 +96,6 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string, return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil } -func (c *Commands) checkLabelPolicyAllowed(ctx context.Context, resourceOwner string, policy *domain.LabelPolicy) error { - defaultPolicy, err := c.getDefaultLabelPolicy(ctx) - if err != nil { - return err - } - requiredFeatures := make([]string, 0) - if defaultPolicy.PrimaryColor != policy.PrimaryColor || defaultPolicy.PrimaryColorDark != policy.PrimaryColorDark || - defaultPolicy.FontColor != policy.FontColor || defaultPolicy.FontColorDark != policy.FontColorDark || - defaultPolicy.BackgroundColor != policy.BackgroundColor || defaultPolicy.BackgroundColorDark != policy.BackgroundColorDark || - defaultPolicy.WarnColor != defaultPolicy.WarnColor || defaultPolicy.WarnColorDark != defaultPolicy.WarnColorDark || - defaultPolicy.LogoURL != policy.LogoURL || defaultPolicy.LogoDarkURL != policy.LogoDarkURL || - defaultPolicy.IconURL != policy.IconURL || defaultPolicy.IconDarkURL != policy.IconDarkURL || - defaultPolicy.Font != policy.Font || - defaultPolicy.HideLoginNameSuffix != policy.HideLoginNameSuffix { - requiredFeatures = append(requiredFeatures, domain.FeatureLabelPolicyPrivateLabel) - } - if defaultPolicy.DisableWatermark != policy.DisableWatermark { - requiredFeatures = append(requiredFeatures, domain.FeatureLabelPolicyWatermark) - } - return c.tokenVerifier.CheckOrgFeatures(ctx, resourceOwner, requiredFeatures...) -} - func (c *Commands) ActivateLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) { if orgID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing") diff --git a/internal/command/org_policy_label_test.go b/internal/command/org_policy_label_test.go index 83b1baeb6..c4fc41edf 100644 --- a/internal/command/org_policy_label_test.go +++ b/internal/command/org_policy_label_test.go @@ -13,7 +13,6 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/policy" "github.com/zitadel/zitadel/internal/static" @@ -22,8 +21,7 @@ import ( func TestCommandSide_AddLabelPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - tokenVerifier orgFeatureChecker + eventstore *eventstore.Eventstore } type args struct { ctx context.Context @@ -104,78 +102,12 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { err: caos_errs.IsErrorAlreadyExists, }, }, - { - name: "add policy, permission denied", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - false, - ), - ), - ), - ), - tokenVerifier: GetMockVerifier(t), - }, - args: args{ - ctx: context.Background(), - orgID: "org1", - policy: &domain.LabelPolicy{ - PrimaryColor: "#ffffff", - BackgroundColor: "#ffffff", - WarnColor: "#ffffff", - FontColor: "#ffffff", - PrimaryColorDark: "#ffffff", - BackgroundColorDark: "#ffffff", - WarnColorDark: "#ffffff", - FontColorDark: "#ffffff", - HideLoginNameSuffix: true, - ErrorMsgPopup: true, - DisableWatermark: true, - }, - }, - res: res{ - err: caos_errs.IsPermissionDenied, - }, - }, { name: "add policy,ok", fields: fields{ eventstore: eventstoreExpect( t, expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - false, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -197,7 +129,6 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { }, ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -240,8 +171,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - tokenVerifier: tt.fields.tokenVerifier, + eventstore: tt.fields.eventstore, } got, err := r.AddLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil { @@ -259,8 +189,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { func TestCommandSide_ChangeLabelPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - tokenVerifier orgFeatureChecker + eventstore *eventstore.Eventstore } type args struct { ctx context.Context @@ -316,71 +245,6 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { err: caos_errs.IsNotFound, }, }, - { - name: "permission denied error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewLabelPolicyAddedEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - true, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - false, - ), - ), - ), - ), - tokenVerifier: GetMockVerifier(t), - }, - args: args{ - ctx: context.Background(), - orgID: "org1", - policy: &domain.LabelPolicy{ - PrimaryColor: "#000000", - BackgroundColor: "#000000", - WarnColor: "#000000", - FontColor: "#000000", - PrimaryColorDark: "#000000", - BackgroundColorDark: "#000000", - WarnColorDark: "#000000", - FontColorDark: "#000000", - HideLoginNameSuffix: true, - ErrorMsgPopup: true, - DisableWatermark: true, - }, - }, - res: res{ - err: caos_errs.IsPermissionDenied, - }, - }, { name: "no changes, precondition error", fields: fields{ @@ -404,26 +268,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - false, - ), - ), - ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -469,24 +314,6 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewLabelPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - "#ffffff", - true, - true, - false, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -508,7 +335,6 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { }, ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -551,8 +377,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - tokenVerifier: tt.fields.tokenVerifier, + eventstore: tt.fields.eventstore, } got, err := r.ChangeLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil { diff --git a/internal/command/org_policy_login.go b/internal/command/org_policy_login.go index 099712bc7..11cc1ece9 100644 --- a/internal/command/org_policy_login.go +++ b/internal/command/org_policy_login.go @@ -2,7 +2,6 @@ package command import ( "context" - "reflect" "github.com/zitadel/logging" @@ -26,11 +25,6 @@ func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, pol return nil, caos_errs.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists") } - err = c.checkLoginPolicyAllowed(ctx, resourceOwner, policy) - if err != nil { - return nil, err - } - orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel) pushedEvents, err := c.eventstore.Push( ctx, @@ -91,11 +85,6 @@ func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string, return nil, caos_errs.ThrowNotFound(nil, "Org-M0sif", "Errors.Org.LoginPolicy.NotFound") } - err = c.checkLoginPolicyAllowed(ctx, resourceOwner, policy) - if err != nil { - return nil, err - } - orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel) changedEvent, hasChanged := existingPolicy.NewChangedEvent( ctx, @@ -127,33 +116,6 @@ func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string, return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil } -func (c *Commands) checkLoginPolicyAllowed(ctx context.Context, resourceOwner string, policy *domain.LoginPolicy) error { - defaultPolicy, err := c.getDefaultLoginPolicy(ctx) - if err != nil { - return err - } - requiredFeatures := make([]string, 0) - if defaultPolicy.ForceMFA != policy.ForceMFA || !reflect.DeepEqual(defaultPolicy.MultiFactors, policy.MultiFactors) || !reflect.DeepEqual(defaultPolicy.SecondFactors, policy.SecondFactors) { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyFactors) - } - if defaultPolicy.AllowExternalIDP != policy.AllowExternalIDP || !reflect.DeepEqual(defaultPolicy.IDPProviders, policy.IDPProviders) { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyIDP) - } - if defaultPolicy.AllowRegister != policy.AllowRegister { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyRegistration) - } - if defaultPolicy.PasswordlessType != policy.PasswordlessType { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyPasswordless) - } - if defaultPolicy.AllowUsernamePassword != policy.AllowUsernamePassword { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyUsernameLogin) - } - if defaultPolicy.HidePasswordReset != policy.HidePasswordReset { - requiredFeatures = append(requiredFeatures, domain.FeatureLoginPolicyPasswordReset) - } - return c.tokenVerifier.CheckOrgFeatures(ctx, resourceOwner, requiredFeatures...) -} - func (c *Commands) RemoveLoginPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) { if orgID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "Org-55Mg9", "Errors.ResourceOwnerMissing") diff --git a/internal/command/org_policy_login_test.go b/internal/command/org_policy_login_test.go index ca7526b38..89d61e8bf 100644 --- a/internal/command/org_policy_login_test.go +++ b/internal/command/org_policy_login_test.go @@ -12,7 +12,6 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/policy" "github.com/zitadel/zitadel/internal/repository/user" @@ -28,8 +27,7 @@ var ( func TestCommandSide_AddLoginPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - tokenVerifier orgFeatureChecker + eventstore *eventstore.Eventstore } type args struct { ctx context.Context @@ -110,77 +108,12 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { err: caos_errs.IsErrorAlreadyExists, }, }, - { - name: "loginpolicy not allowed, permission denied error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - ), - tokenVerifier: GetMockVerifier(t), - }, - args: args{ - ctx: context.Background(), - orgID: "org1", - policy: &domain.LoginPolicy{ - AllowRegister: true, - AllowUsernamePassword: true, - AllowExternalIDP: true, - ForceMFA: true, - PasswordlessType: domain.PasswordlessTypeAllowed, - PasswordCheckLifetime: time.Hour * 1, - ExternalLoginCheckLifetime: time.Hour * 2, - MFAInitSkipLifetime: time.Hour * 3, - SecondFactorCheckLifetime: time.Hour * 4, - MultiFactorCheckLifetime: time.Hour * 5, - }, - }, - res: res{ - err: caos_errs.IsPermissionDenied, - }, - }, { name: "add policy,ok", fields: fields{ eventstore: eventstoreExpect( t, expectFilter(), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -202,7 +135,6 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { }, ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLoginPolicyUsernameLogin), }, args: args{ ctx: context.Background(), @@ -245,8 +177,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - tokenVerifier: tt.fields.tokenVerifier, + eventstore: tt.fields.eventstore, } got, err := r.AddLoginPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil { @@ -264,8 +195,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { func TestCommandSide_ChangeLoginPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - tokenVerifier orgFeatureChecker + eventstore *eventstore.Eventstore } type args struct { ctx context.Context @@ -326,70 +256,6 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { err: caos_errs.IsNotFound, }, }, - { - name: "not allowed, permission denied error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - org.NewLoginPolicyAddedEvent(context.Background(), - &org.NewAggregate("org1").Aggregate, - true, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), - ), - tokenVerifier: GetMockVerifier(t), - }, - args: args{ - ctx: context.Background(), - orgID: "org1", - policy: &domain.LoginPolicy{ - AllowRegister: true, - AllowUsernamePassword: true, - AllowExternalIDP: true, - ForceMFA: true, - PasswordlessType: domain.PasswordlessTypeAllowed, - PasswordCheckLifetime: time.Hour * 1, - ExternalLoginCheckLifetime: time.Hour * 2, - MFAInitSkipLifetime: time.Hour * 3, - SecondFactorCheckLifetime: time.Hour * 4, - MultiFactorCheckLifetime: time.Hour * 5, - }, - }, - res: res{ - err: caos_errs.IsPermissionDenied, - }, - }, { name: "no changes, precondition error", fields: fields{ @@ -413,26 +279,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - true, - true, - true, - true, - domain.PasswordlessTypeAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLoginPolicyUsernameLogin), }, args: args{ ctx: context.Background(), @@ -478,24 +325,6 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewLoginPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - false, - false, - false, - false, - false, - domain.PasswordlessTypeNotAllowed, - time.Hour*1, - time.Hour*2, - time.Hour*3, - time.Hour*4, - time.Hour*5, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -517,7 +346,6 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { }, ), ), - tokenVerifier: GetMockVerifier(t, domain.FeatureLoginPolicyUsernameLogin), }, args: args{ ctx: context.Background(), @@ -559,8 +387,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - tokenVerifier: tt.fields.tokenVerifier, + eventstore: tt.fields.eventstore, } got, err := r.ChangeLoginPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil { diff --git a/internal/domain/features.go b/internal/domain/features.go deleted file mode 100644 index d5bd9098c..000000000 --- a/internal/domain/features.go +++ /dev/null @@ -1,76 +0,0 @@ -package domain - -import ( - "time" - - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -const ( - FeatureLoginPolicy = "login_policy" - FeatureLoginPolicyFactors = FeatureLoginPolicy + ".factors" - FeatureLoginPolicyIDP = FeatureLoginPolicy + ".idp" - FeatureLoginPolicyPasswordless = FeatureLoginPolicy + ".passwordless" - FeatureLoginPolicyRegistration = FeatureLoginPolicy + ".registration" - FeatureLoginPolicyUsernameLogin = FeatureLoginPolicy + ".username_login" - FeatureLoginPolicyPasswordReset = FeatureLoginPolicy + ".password_reset" - FeaturePasswordComplexityPolicy = "password_complexity_policy" - FeatureLabelPolicy = "label_policy" - FeatureLabelPolicyPrivateLabel = FeatureLabelPolicy + ".private_label" - FeatureLabelPolicyWatermark = FeatureLabelPolicy + ".watermark" - FeatureCustomDomain = "custom_domain" - FeaturePrivacyPolicy = "privacy_policy" - FeatureLockoutPolicy = "lockout_policy" - FeatureMetadata = "metadata" - FeatureCustomText = "custom_text" - FeatureCustomTextMessage = FeatureCustomText + ".message" - FeatureCustomTextLogin = FeatureCustomText + ".login" - FeatureMetadataUser = FeatureMetadata + ".user" - FeatureActions = "actions" -) - -type Features struct { - es_models.ObjectRoot - - TierName string - TierDescription string - State FeaturesState - StateDescription string - IsDefault bool - - AuditLogRetention time.Duration - LoginPolicyFactors bool - LoginPolicyIDP bool - LoginPolicyPasswordless bool - LoginPolicyRegistration bool - LoginPolicyUsernameLogin bool - LoginPolicyPasswordReset bool - PasswordComplexityPolicy bool - LabelPolicyPrivateLabel bool - LabelPolicyWatermark bool - CustomDomain bool - CustomTextMessage bool - CustomTextLogin bool - PrivacyPolicy bool - MetadataUser bool - LockoutPolicy bool - ActionsAllowed ActionsAllowed - MaxActions int -} - -type FeaturesState int32 - -const ( - FeaturesStateUnspecified FeaturesState = iota - FeaturesStateActive - FeaturesStateActionRequired - FeaturesStateCanceled - FeaturesStateGrandfathered - FeaturesStateRemoved - - featuresStateCount -) - -func (f FeaturesState) Valid() bool { - return f >= 0 && f < featuresStateCount -} diff --git a/internal/protoc/protoc-gen-authoption/templates/auth_method_mapping.go.tmpl b/internal/protoc/protoc-gen-authoption/templates/auth_method_mapping.go.tmpl index cfc71fb5c..bd6fe3b88 100644 --- a/internal/protoc/protoc-gen-authoption/templates/auth_method_mapping.go.tmpl +++ b/internal/protoc/protoc-gen-authoption/templates/auth_method_mapping.go.tmpl @@ -21,14 +21,13 @@ const {{$s.Name}}_MethodPrefix = "{{$.File.Package}}.{{$s.Name}}" var {{$s.Name}}_AuthMethods = authz.MethodMapping { {{ range $m := $s.Method}} {{ $mAuthOpt := option $m.Options "zitadel.v1.auth_option" }} - {{ if and $mAuthOpt (or $mAuthOpt.Permission $mAuthOpt.Feature) }} + {{ if and $mAuthOpt $mAuthOpt.Permission }} "/{{$.File.Package}}.{{$s.Name}}/{{.Name}}": authz.Option{ Permission: "{{$mAuthOpt.Permission}}", CheckParam: "{{$mAuthOpt.CheckFieldName}}", - Feature: "{{$mAuthOpt.Feature}}", }, {{end}} {{ end}} } -{{ end }} \ No newline at end of file +{{ end }} diff --git a/internal/query/changes.go b/internal/query/changes.go index bc455e00f..180dc8ea7 100644 --- a/internal/query/changes.go +++ b/internal/query/changes.go @@ -87,7 +87,7 @@ func (q *Queries) changes(ctx context.Context, query func(query *eventstore.Sear } changes := make([]*Change, 0, len(events)) for _, event := range events { - if event.CreationDate().Before(time.Now().Add(-auditLogRetention)) { + if auditLogRetention != 0 && event.CreationDate().Before(time.Now().Add(-auditLogRetention)) { continue } change := &Change{ diff --git a/internal/query/features.go b/internal/query/features.go deleted file mode 100644 index 6e93345af..000000000 --- a/internal/query/features.go +++ /dev/null @@ -1,327 +0,0 @@ -package query - -import ( - "context" - "database/sql" - errs "errors" - "time" - - sq "github.com/Masterminds/squirrel" - - "github.com/zitadel/zitadel/internal/api/authz" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/query/projection" -) - -type Features struct { - AggregateID string - ChangeDate time.Time - Sequence uint64 - IsDefault bool - TierName string - TierDescription string - State domain.FeaturesState - StateDescription string - AuditLogRetention time.Duration - LoginPolicyFactors bool - LoginPolicyIDP bool - LoginPolicyPasswordless bool - LoginPolicyRegistration bool - LoginPolicyUsernameLogin bool - LoginPolicyPasswordReset bool - PasswordComplexityPolicy bool - LabelPolicyPrivateLabel bool - LabelPolicyWatermark bool - CustomDomain bool - PrivacyPolicy bool - MetadataUser bool - CustomTextMessage bool - CustomTextLogin bool - LockoutPolicy bool - ActionsAllowed domain.ActionsAllowed - MaxActions int32 -} - -var ( - featureTable = table{ - name: projection.FeatureTable, - } - FeatureColumnAggregateID = Column{ - name: projection.FeatureAggregateIDCol, - table: featureTable, - } - FeatureColumnInstanceID = Column{ - name: projection.FeatureInstanceIDCol, - table: featureTable, - } - FeatureColumnChangeDate = Column{ - name: projection.FeatureChangeDateCol, - table: featureTable, - } - FeatureColumnSequence = Column{ - name: projection.FeatureSequenceCol, - table: featureTable, - } - FeatureColumnIsDefault = Column{ - name: projection.FeatureIsDefaultCol, - table: featureTable, - } - FeatureTierName = Column{ - name: projection.FeatureTierNameCol, - table: featureTable, - } - FeatureTierDescription = Column{ - name: projection.FeatureTierDescriptionCol, - table: featureTable, - } - FeatureState = Column{ - name: projection.FeatureStateCol, - table: featureTable, - } - FeatureStateDescription = Column{ - name: projection.FeatureStateDescriptionCol, - table: featureTable, - } - FeatureAuditLogRetention = Column{ - name: projection.FeatureAuditLogRetentionCol, - table: featureTable, - } - FeatureLoginPolicyFactors = Column{ - name: projection.FeatureLoginPolicyFactorsCol, - table: featureTable, - } - FeatureLoginPolicyIDP = Column{ - name: projection.FeatureLoginPolicyIDPCol, - table: featureTable, - } - FeatureLoginPolicyPasswordless = Column{ - name: projection.FeatureLoginPolicyPasswordlessCol, - table: featureTable, - } - FeatureLoginPolicyRegistration = Column{ - name: projection.FeatureLoginPolicyRegistrationCol, - table: featureTable, - } - FeatureLoginPolicyUsernameLogin = Column{ - name: projection.FeatureLoginPolicyUsernameLoginCol, - table: featureTable, - } - FeatureLoginPolicyPasswordReset = Column{ - name: projection.FeatureLoginPolicyPasswordResetCol, - table: featureTable, - } - FeaturePasswordComplexityPolicy = Column{ - name: projection.FeaturePasswordComplexityPolicyCol, - table: featureTable, - } - FeatureLabelPolicyPrivateLabel = Column{ - name: projection.FeatureLabelPolicyPrivateLabelCol, - table: featureTable, - } - FeatureLabelPolicyWatermark = Column{ - name: projection.FeatureLabelPolicyWatermarkCol, - table: featureTable, - } - FeatureCustomDomain = Column{ - name: projection.FeatureCustomDomainCol, - table: featureTable, - } - FeaturePrivacyPolicy = Column{ - name: projection.FeaturePrivacyPolicyCol, - table: featureTable, - } - FeatureMetadataUser = Column{ - name: projection.FeatureMetadataUserCol, - table: featureTable, - } - FeatureCustomTextMessage = Column{ - name: projection.FeatureCustomTextMessageCol, - table: featureTable, - } - FeatureCustomTextLogin = Column{ - name: projection.FeatureCustomTextLoginCol, - table: featureTable, - } - FeatureLockoutPolicy = Column{ - name: projection.FeatureLockoutPolicyCol, - table: featureTable, - } - FeatureActionsAllowed = Column{ - name: projection.FeatureActionsAllowedCol, - table: featureTable, - } - FeatureMaxActions = Column{ - name: projection.FeatureMaxActionsCol, - table: featureTable, - } -) - -func (q *Queries) FeaturesByOrgID(ctx context.Context, orgID string) (*Features, error) { - query, scan := prepareFeaturesQuery() - stmt, args, err := query.Where( - sq.And{ - sq.Eq{ - FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - sq.Or{ - sq.Eq{ - FeatureColumnAggregateID.identifier(): orgID, - }, - sq.Eq{ - FeatureColumnAggregateID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - }, - }). - OrderBy(FeatureColumnIsDefault.identifier()). - Limit(1).ToSql() - if err != nil { - return nil, errors.ThrowInternal(err, "QUERY-P9gwg", "Errors.Query.SQLStatement") - } - - row := q.client.QueryRowContext(ctx, stmt, args...) - return scan(row) -} - -func (q *Queries) DefaultFeatures(ctx context.Context) (*Features, error) { - query, scan := prepareFeaturesQuery() - stmt, args, err := query.Where(sq.Eq{ - FeatureColumnAggregateID.identifier(): authz.GetInstance(ctx).InstanceID(), - FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() - if err != nil { - return nil, errors.ThrowInternal(err, "QUERY-1Ndlg", "Errors.Query.SQLStatement") - } - - row := q.client.QueryRowContext(ctx, stmt, args...) - return scan(row) -} - -func prepareFeaturesQuery() (sq.SelectBuilder, func(*sql.Row) (*Features, error)) { - return sq.Select( - FeatureColumnAggregateID.identifier(), - FeatureColumnChangeDate.identifier(), - FeatureColumnSequence.identifier(), - FeatureColumnIsDefault.identifier(), - FeatureTierName.identifier(), - FeatureTierDescription.identifier(), - FeatureState.identifier(), - FeatureStateDescription.identifier(), - FeatureAuditLogRetention.identifier(), - FeatureLoginPolicyFactors.identifier(), - FeatureLoginPolicyIDP.identifier(), - FeatureLoginPolicyPasswordless.identifier(), - FeatureLoginPolicyRegistration.identifier(), - FeatureLoginPolicyUsernameLogin.identifier(), - FeatureLoginPolicyPasswordReset.identifier(), - FeaturePasswordComplexityPolicy.identifier(), - FeatureLabelPolicyPrivateLabel.identifier(), - FeatureLabelPolicyWatermark.identifier(), - FeatureCustomDomain.identifier(), - FeaturePrivacyPolicy.identifier(), - FeatureMetadataUser.identifier(), - FeatureCustomTextMessage.identifier(), - FeatureCustomTextLogin.identifier(), - FeatureLockoutPolicy.identifier(), - FeatureActionsAllowed.identifier(), - FeatureMaxActions.identifier(), - ).From(featureTable.identifier()).PlaceholderFormat(sq.Dollar), - func(row *sql.Row) (*Features, error) { - p := new(Features) - tierName := sql.NullString{} - tierDescription := sql.NullString{} - stateDescription := sql.NullString{} - err := row.Scan( - &p.AggregateID, - &p.ChangeDate, - &p.Sequence, - &p.IsDefault, - &tierName, - &tierDescription, - &p.State, - &stateDescription, - &p.AuditLogRetention, - &p.LoginPolicyFactors, - &p.LoginPolicyIDP, - &p.LoginPolicyPasswordless, - &p.LoginPolicyRegistration, - &p.LoginPolicyUsernameLogin, - &p.LoginPolicyPasswordReset, - &p.PasswordComplexityPolicy, - &p.LabelPolicyPrivateLabel, - &p.LabelPolicyWatermark, - &p.CustomDomain, - &p.PrivacyPolicy, - &p.MetadataUser, - &p.CustomTextMessage, - &p.CustomTextLogin, - &p.LockoutPolicy, - &p.ActionsAllowed, - &p.MaxActions, - ) - if err != nil { - if errs.Is(err, sql.ErrNoRows) { - return nil, errors.ThrowNotFound(err, "QUERY-M9fse", "Errors.Features.NotFound") - } - return nil, errors.ThrowInternal(err, "QUERY-3o9gd", "Errors.Internal") - } - p.TierName = tierName.String - p.TierDescription = tierDescription.String - p.StateDescription = stateDescription.String - return p, nil - } -} - -func (f *Features) EnabledFeatureTypes() []string { - list := make([]string, 0) - if f.LoginPolicyFactors { - list = append(list, domain.FeatureLoginPolicyFactors) - } - if f.LoginPolicyIDP { - list = append(list, domain.FeatureLoginPolicyIDP) - } - if f.LoginPolicyPasswordless { - list = append(list, domain.FeatureLoginPolicyPasswordless) - } - if f.LoginPolicyRegistration { - list = append(list, domain.FeatureLoginPolicyRegistration) - } - if f.LoginPolicyUsernameLogin { - list = append(list, domain.FeatureLoginPolicyUsernameLogin) - } - if f.LoginPolicyPasswordReset { - list = append(list, domain.FeatureLoginPolicyPasswordReset) - } - if f.PasswordComplexityPolicy { - list = append(list, domain.FeaturePasswordComplexityPolicy) - } - if f.LabelPolicyPrivateLabel { - list = append(list, domain.FeatureLabelPolicyPrivateLabel) - } - if f.LabelPolicyWatermark { - list = append(list, domain.FeatureLabelPolicyWatermark) - } - if f.CustomDomain { - list = append(list, domain.FeatureCustomDomain) - } - if f.PrivacyPolicy { - list = append(list, domain.FeaturePrivacyPolicy) - } - if f.MetadataUser { - list = append(list, domain.FeatureMetadataUser) - } - if f.CustomTextMessage { - list = append(list, domain.FeatureCustomTextMessage) - } - if f.CustomTextLogin { - list = append(list, domain.FeatureCustomTextLogin) - } - if f.LockoutPolicy { - list = append(list, domain.FeatureLockoutPolicy) - } - if f.ActionsAllowed != domain.ActionsNotAllowed { - list = append(list, domain.FeatureActions) - } - return list -} diff --git a/internal/query/features_test.go b/internal/query/features_test.go deleted file mode 100644 index daa11b31e..000000000 --- a/internal/query/features_test.go +++ /dev/null @@ -1,358 +0,0 @@ -package query - -import ( - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "regexp" - "testing" - "time" - - "github.com/zitadel/zitadel/internal/domain" - errs "github.com/zitadel/zitadel/internal/errors" -) - -func Test_FeaturesPrepares(t *testing.T) { - type want struct { - sqlExpectations sqlExpectation - err checkErr - } - tests := []struct { - name string - prepare interface{} - want want - object interface{} - }{ - { - name: "prepareFeaturesQuery no result", - prepare: prepareFeaturesQuery, - want: want{ - sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.features.aggregate_id,`+ - ` projections.features.change_date,`+ - ` projections.features.sequence,`+ - ` projections.features.is_default,`+ - ` projections.features.tier_name,`+ - ` projections.features.tier_description,`+ - ` projections.features.state,`+ - ` projections.features.state_description,`+ - ` projections.features.audit_log_retention,`+ - ` projections.features.login_policy_factors,`+ - ` projections.features.login_policy_idp,`+ - ` projections.features.login_policy_passwordless,`+ - ` projections.features.login_policy_registration,`+ - ` projections.features.login_policy_username_login,`+ - ` projections.features.login_policy_password_reset,`+ - ` projections.features.password_complexity_policy,`+ - ` projections.features.label_policy_private_label,`+ - ` projections.features.label_policy_watermark,`+ - ` projections.features.custom_domain,`+ - ` projections.features.privacy_policy,`+ - ` projections.features.metadata_user,`+ - ` projections.features.custom_text_message,`+ - ` projections.features.custom_text_login,`+ - ` projections.features.lockout_policy,`+ - ` projections.features.actions_allowed,`+ - ` projections.features.max_actions`+ - ` FROM projections.features`), - nil, - nil, - ), - err: func(err error) (error, bool) { - if !errs.IsNotFound(err) { - return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false - } - return nil, true - }, - }, - object: (*Features)(nil), - }, - { - name: "prepareFeaturesQuery found", - prepare: prepareFeaturesQuery, - want: want{ - sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.features.aggregate_id,`+ - ` projections.features.change_date,`+ - ` projections.features.sequence,`+ - ` projections.features.is_default,`+ - ` projections.features.tier_name,`+ - ` projections.features.tier_description,`+ - ` projections.features.state,`+ - ` projections.features.state_description,`+ - ` projections.features.audit_log_retention,`+ - ` projections.features.login_policy_factors,`+ - ` projections.features.login_policy_idp,`+ - ` projections.features.login_policy_passwordless,`+ - ` projections.features.login_policy_registration,`+ - ` projections.features.login_policy_username_login,`+ - ` projections.features.login_policy_password_reset,`+ - ` projections.features.password_complexity_policy,`+ - ` projections.features.label_policy_private_label,`+ - ` projections.features.label_policy_watermark,`+ - ` projections.features.custom_domain,`+ - ` projections.features.privacy_policy,`+ - ` projections.features.metadata_user,`+ - ` projections.features.custom_text_message,`+ - ` projections.features.custom_text_login,`+ - ` projections.features.lockout_policy,`+ - ` projections.features.actions_allowed,`+ - ` projections.features.max_actions`+ - ` FROM projections.features`), - []string{ - "aggregate_id", - "change_date", - "sequence", - "is_default", - "tier_name", - "tier_description", - "state", - "state_description", - "audit_log_retention", - "login_policy_factors", - "login_policy_idp", - "login_policy_passwordless", - "login_policy_registration", - "login_policy_username_login", - "login_policy_password_reset", - "password_complexity_policy", - "label_policy_private_label", - "label_policy_watermark", - "custom_domain", - "privacy_policy", - "metadata_user", - "custom_text_message", - "custom_text_login", - "lockout_policy", - "actions_allowed", - "max_actions", - }, - []driver.Value{ - "aggregate-id", - testNow, - uint64(20211115), - true, - "tier-name", - "tier-description", - 1, - "state-description", - uint(604800000000000), // 7days in nanoseconds - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsMaxAllowed, - 10, - }, - ), - }, - object: &Features{ - AggregateID: "aggregate-id", - ChangeDate: testNow, - Sequence: 20211115, - IsDefault: true, - TierName: "tier-name", - TierDescription: "tier-description", - State: domain.FeaturesStateActive, - StateDescription: "state-description", - AuditLogRetention: 7 * 24 * time.Hour, - LoginPolicyFactors: true, - LoginPolicyIDP: true, - LoginPolicyPasswordless: true, - LoginPolicyRegistration: true, - LoginPolicyUsernameLogin: true, - LoginPolicyPasswordReset: true, - PasswordComplexityPolicy: true, - LabelPolicyPrivateLabel: true, - LabelPolicyWatermark: true, - CustomDomain: true, - PrivacyPolicy: true, - MetadataUser: true, - CustomTextMessage: true, - CustomTextLogin: true, - LockoutPolicy: true, - ActionsAllowed: domain.ActionsMaxAllowed, - MaxActions: 10, - }, - }, - { - name: "prepareFeaturesQuery found with empty", - prepare: prepareFeaturesQuery, - want: want{ - sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.features.aggregate_id,`+ - ` projections.features.change_date,`+ - ` projections.features.sequence,`+ - ` projections.features.is_default,`+ - ` projections.features.tier_name,`+ - ` projections.features.tier_description,`+ - ` projections.features.state,`+ - ` projections.features.state_description,`+ - ` projections.features.audit_log_retention,`+ - ` projections.features.login_policy_factors,`+ - ` projections.features.login_policy_idp,`+ - ` projections.features.login_policy_passwordless,`+ - ` projections.features.login_policy_registration,`+ - ` projections.features.login_policy_username_login,`+ - ` projections.features.login_policy_password_reset,`+ - ` projections.features.password_complexity_policy,`+ - ` projections.features.label_policy_private_label,`+ - ` projections.features.label_policy_watermark,`+ - ` projections.features.custom_domain,`+ - ` projections.features.privacy_policy,`+ - ` projections.features.metadata_user,`+ - ` projections.features.custom_text_message,`+ - ` projections.features.custom_text_login,`+ - ` projections.features.lockout_policy,`+ - ` projections.features.actions_allowed,`+ - ` projections.features.max_actions`+ - ` FROM projections.features`), - []string{ - "aggregate_id", - "change_date", - "sequence", - "is_default", - "tier_name", - "tier_description", - "state", - "state_description", - "audit_log_retention", - "login_policy_factors", - "login_policy_idp", - "login_policy_passwordless", - "login_policy_registration", - "login_policy_username_login", - "login_policy_password_reset", - "password_complexity_policy", - "label_policy_private_label", - "label_policy_watermark", - "custom_domain", - "privacy_policy", - "metadata_user", - "custom_text_message", - "custom_text_login", - "lockout_policy", - "actions_allowed", - "max_actions", - }, - []driver.Value{ - "aggregate-id", - testNow, - uint64(20211115), - true, - nil, - nil, - 1, - nil, - uint(604800000000000), // 7days in nanoseconds - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsMaxAllowed, - 10, - }, - ), - }, - object: &Features{ - AggregateID: "aggregate-id", - ChangeDate: testNow, - Sequence: 20211115, - IsDefault: true, - TierName: "", - TierDescription: "", - State: domain.FeaturesStateActive, - StateDescription: "", - AuditLogRetention: 7 * 24 * time.Hour, - LoginPolicyFactors: true, - LoginPolicyIDP: true, - LoginPolicyPasswordless: true, - LoginPolicyRegistration: true, - LoginPolicyUsernameLogin: true, - LoginPolicyPasswordReset: true, - PasswordComplexityPolicy: true, - LabelPolicyPrivateLabel: true, - LabelPolicyWatermark: true, - CustomDomain: true, - PrivacyPolicy: true, - MetadataUser: true, - CustomTextMessage: true, - CustomTextLogin: true, - LockoutPolicy: true, - ActionsAllowed: domain.ActionsMaxAllowed, - MaxActions: 10, - }, - }, - { - name: "prepareFeaturesQuery sql err", - prepare: prepareFeaturesQuery, - want: want{ - sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.features.aggregate_id,`+ - ` projections.features.change_date,`+ - ` projections.features.sequence,`+ - ` projections.features.is_default,`+ - ` projections.features.tier_name,`+ - ` projections.features.tier_description,`+ - ` projections.features.state,`+ - ` projections.features.state_description,`+ - ` projections.features.audit_log_retention,`+ - ` projections.features.login_policy_factors,`+ - ` projections.features.login_policy_idp,`+ - ` projections.features.login_policy_passwordless,`+ - ` projections.features.login_policy_registration,`+ - ` projections.features.login_policy_username_login,`+ - ` projections.features.login_policy_password_reset,`+ - ` projections.features.password_complexity_policy,`+ - ` projections.features.label_policy_private_label,`+ - ` projections.features.label_policy_watermark,`+ - ` projections.features.custom_domain,`+ - ` projections.features.privacy_policy,`+ - ` projections.features.metadata_user,`+ - ` projections.features.custom_text_message,`+ - ` projections.features.custom_text_login,`+ - ` projections.features.lockout_policy,`+ - ` projections.features.actions_allowed,`+ - ` projections.features.max_actions`+ - ` FROM projections.features`), - sql.ErrConnDone, - ), - err: func(err error) (error, bool) { - if !errors.Is(err, sql.ErrConnDone) { - return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false - } - return nil, true - }, - }, - object: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err) - }) - } -} diff --git a/internal/query/projection/feature.go b/internal/query/projection/feature.go deleted file mode 100644 index 7f8ca8638..000000000 --- a/internal/query/projection/feature.go +++ /dev/null @@ -1,237 +0,0 @@ -package projection - -import ( - "context" - - "github.com/zitadel/zitadel/internal/domain" - - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/handler" - "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" - "github.com/zitadel/zitadel/internal/repository/features" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" -) - -const ( - FeatureTable = "projections.features" - - FeatureAggregateIDCol = "aggregate_id" - FeatureInstanceIDCol = "instance_id" - FeatureChangeDateCol = "change_date" - FeatureSequenceCol = "sequence" - FeatureIsDefaultCol = "is_default" - FeatureTierNameCol = "tier_name" - FeatureTierDescriptionCol = "tier_description" - FeatureStateCol = "state" - FeatureStateDescriptionCol = "state_description" - FeatureAuditLogRetentionCol = "audit_log_retention" - FeatureLoginPolicyFactorsCol = "login_policy_factors" - FeatureLoginPolicyIDPCol = "login_policy_idp" - FeatureLoginPolicyPasswordlessCol = "login_policy_passwordless" - FeatureLoginPolicyRegistrationCol = "login_policy_registration" - FeatureLoginPolicyUsernameLoginCol = "login_policy_username_login" - FeatureLoginPolicyPasswordResetCol = "login_policy_password_reset" - FeaturePasswordComplexityPolicyCol = "password_complexity_policy" - FeatureLabelPolicyPrivateLabelCol = "label_policy_private_label" - FeatureLabelPolicyWatermarkCol = "label_policy_watermark" - FeatureCustomDomainCol = "custom_domain" - FeaturePrivacyPolicyCol = "privacy_policy" - FeatureMetadataUserCol = "metadata_user" - FeatureCustomTextMessageCol = "custom_text_message" - FeatureCustomTextLoginCol = "custom_text_login" - FeatureLockoutPolicyCol = "lockout_policy" - FeatureActionsAllowedCol = "actions_allowed" - FeatureMaxActionsCol = "max_actions" -) - -type FeatureProjection struct { - crdb.StatementHandler -} - -func NewFeatureProjection(ctx context.Context, config crdb.StatementHandlerConfig) *FeatureProjection { - p := new(FeatureProjection) - config.ProjectionName = FeatureTable - config.Reducers = p.reducers() - config.InitCheck = crdb.NewTableCheck( - crdb.NewTable([]*crdb.Column{ - crdb.NewColumn(FeatureAggregateIDCol, crdb.ColumnTypeText), - crdb.NewColumn(FeatureInstanceIDCol, crdb.ColumnTypeText), - crdb.NewColumn(FeatureChangeDateCol, crdb.ColumnTypeTimestamp), - crdb.NewColumn(FeatureSequenceCol, crdb.ColumnTypeInt64), - crdb.NewColumn(FeatureIsDefaultCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureTierNameCol, crdb.ColumnTypeText), - crdb.NewColumn(FeatureTierDescriptionCol, crdb.ColumnTypeText, crdb.Nullable()), - crdb.NewColumn(FeatureStateCol, crdb.ColumnTypeEnum, crdb.Default(0)), - crdb.NewColumn(FeatureStateDescriptionCol, crdb.ColumnTypeText, crdb.Nullable()), - crdb.NewColumn(FeatureAuditLogRetentionCol, crdb.ColumnTypeInt64, crdb.Default(0)), - crdb.NewColumn(FeatureLoginPolicyFactorsCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLoginPolicyIDPCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLoginPolicyPasswordlessCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLoginPolicyRegistrationCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLoginPolicyUsernameLoginCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLoginPolicyPasswordResetCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeaturePasswordComplexityPolicyCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLabelPolicyPrivateLabelCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLabelPolicyWatermarkCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureCustomDomainCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeaturePrivacyPolicyCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureMetadataUserCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureCustomTextMessageCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureCustomTextLoginCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureLockoutPolicyCol, crdb.ColumnTypeBool, crdb.Default(false)), - crdb.NewColumn(FeatureActionsAllowedCol, crdb.ColumnTypeEnum, crdb.Default(0)), - crdb.NewColumn(FeatureMaxActionsCol, crdb.ColumnTypeInt64, crdb.Default(0)), - }, - crdb.NewPrimaryKey(FeatureInstanceIDCol, FeatureAggregateIDCol), - ), - ) - p.StatementHandler = crdb.NewStatementHandler(ctx, config) - return p -} - -func (p *FeatureProjection) reducers() []handler.AggregateReducer { - return []handler.AggregateReducer{ - { - Aggregate: org.AggregateType, - EventRedusers: []handler.EventReducer{ - { - Event: org.FeaturesSetEventType, - Reduce: p.reduceFeatureSet, - }, - { - Event: org.FeaturesRemovedEventType, - Reduce: p.reduceFeatureRemoved, - }, - }, - }, - { - Aggregate: instance.AggregateType, - EventRedusers: []handler.EventReducer{ - { - Event: instance.FeaturesSetEventType, - Reduce: p.reduceFeatureSet, - }, - }, - }, - } -} - -func (p *FeatureProjection) reduceFeatureSet(event eventstore.Event) (*handler.Statement, error) { - var featureEvent features.FeaturesSetEvent - var isDefault bool - switch e := event.(type) { - case *instance.FeaturesSetEvent: - featureEvent = e.FeaturesSetEvent - isDefault = true - case *org.FeaturesSetEvent: - featureEvent = e.FeaturesSetEvent - isDefault = false - default: - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-K0erf", "reduce.wrong.event.type %v", []eventstore.EventType{org.FeaturesSetEventType, instance.FeaturesSetEventType}) - } - - cols := []handler.Column{ - handler.NewCol(FeatureAggregateIDCol, featureEvent.Aggregate().ID), - handler.NewCol(FeatureInstanceIDCol, featureEvent.Aggregate().InstanceID), - handler.NewCol(FeatureChangeDateCol, featureEvent.CreationDate()), - handler.NewCol(FeatureSequenceCol, featureEvent.Sequence()), - handler.NewCol(FeatureIsDefaultCol, isDefault), - } - if featureEvent.TierName != nil { - cols = append(cols, handler.NewCol(FeatureTierNameCol, *featureEvent.TierName)) - } - if featureEvent.TierDescription != nil { - cols = append(cols, handler.NewCol(FeatureTierDescriptionCol, *featureEvent.TierDescription)) - } - if featureEvent.State != nil { - cols = append(cols, handler.NewCol(FeatureStateCol, *featureEvent.State)) - } - if featureEvent.StateDescription != nil { - cols = append(cols, handler.NewCol(FeatureStateDescriptionCol, *featureEvent.StateDescription)) - } - if featureEvent.AuditLogRetention != nil { - cols = append(cols, handler.NewCol(FeatureAuditLogRetentionCol, *featureEvent.AuditLogRetention)) - } - if featureEvent.LoginPolicyFactors != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyFactorsCol, *featureEvent.LoginPolicyFactors)) - } - if featureEvent.LoginPolicyIDP != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyIDPCol, *featureEvent.LoginPolicyIDP)) - } - if featureEvent.LoginPolicyPasswordless != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyPasswordlessCol, *featureEvent.LoginPolicyPasswordless)) - } - if featureEvent.LoginPolicyRegistration != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyRegistrationCol, *featureEvent.LoginPolicyRegistration)) - } - if featureEvent.LoginPolicyUsernameLogin != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyUsernameLoginCol, *featureEvent.LoginPolicyUsernameLogin)) - } - if featureEvent.LoginPolicyPasswordReset != nil { - cols = append(cols, handler.NewCol(FeatureLoginPolicyPasswordResetCol, *featureEvent.LoginPolicyPasswordReset)) - } - if featureEvent.PasswordComplexityPolicy != nil { - cols = append(cols, handler.NewCol(FeaturePasswordComplexityPolicyCol, *featureEvent.PasswordComplexityPolicy)) - } - if featureEvent.LabelPolicyPrivateLabel != nil || featureEvent.LabelPolicy != nil { - var value bool - if featureEvent.LabelPolicyPrivateLabel != nil { - value = *featureEvent.LabelPolicyPrivateLabel - } else { - value = *featureEvent.LabelPolicy - } - cols = append(cols, handler.NewCol(FeatureLabelPolicyPrivateLabelCol, value)) - } - if featureEvent.LabelPolicyWatermark != nil { - cols = append(cols, handler.NewCol(FeatureLabelPolicyWatermarkCol, *featureEvent.LabelPolicyWatermark)) - } - if featureEvent.CustomDomain != nil { - cols = append(cols, handler.NewCol(FeatureCustomDomainCol, *featureEvent.CustomDomain)) - } - if featureEvent.PrivacyPolicy != nil { - cols = append(cols, handler.NewCol(FeaturePrivacyPolicyCol, *featureEvent.PrivacyPolicy)) - } - if featureEvent.MetadataUser != nil { - cols = append(cols, handler.NewCol(FeatureMetadataUserCol, *featureEvent.MetadataUser)) - } - if featureEvent.CustomTextMessage != nil { - cols = append(cols, handler.NewCol(FeatureCustomTextMessageCol, *featureEvent.CustomTextMessage)) - } - if featureEvent.CustomTextLogin != nil { - cols = append(cols, handler.NewCol(FeatureCustomTextLoginCol, *featureEvent.CustomTextLogin)) - } - if featureEvent.LockoutPolicy != nil { - cols = append(cols, handler.NewCol(FeatureLockoutPolicyCol, *featureEvent.LockoutPolicy)) - } - if featureEvent.Actions != nil { - actionsAllowed := domain.ActionsNotAllowed - if *featureEvent.Actions { - actionsAllowed = domain.ActionsAllowedUnlimited - } - cols = append(cols, handler.NewCol(FeatureActionsAllowedCol, actionsAllowed)) - } - if featureEvent.ActionsAllowed != nil { - cols = append(cols, handler.NewCol(FeatureActionsAllowedCol, *featureEvent.ActionsAllowed)) - } - if featureEvent.MaxActions != nil { - cols = append(cols, handler.NewCol(FeatureMaxActionsCol, *featureEvent.MaxActions)) - } - return crdb.NewUpsertStatement( - &featureEvent, - cols), nil -} - -func (p *FeatureProjection) reduceFeatureRemoved(event eventstore.Event) (*handler.Statement, error) { - e, ok := event.(*org.FeaturesRemovedEvent) - if !ok { - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-0p4rf", "reduce.wrong.event.type %s", org.FeaturesRemovedEventType) - } - return crdb.NewDeleteStatement( - e, - []handler.Condition{ - handler.NewCond(FeatureAggregateIDCol, e.Aggregate().ID), - }, - ), nil -} diff --git a/internal/query/projection/feature_test.go b/internal/query/projection/feature_test.go deleted file mode 100644 index af758b008..000000000 --- a/internal/query/projection/feature_test.go +++ /dev/null @@ -1,398 +0,0 @@ -package projection - -import ( - "testing" - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/handler" - "github.com/zitadel/zitadel/internal/eventstore/repository" - "github.com/zitadel/zitadel/internal/repository/instance" - "github.com/zitadel/zitadel/internal/repository/org" -) - -func TestFeatureProjection_reduces(t *testing.T) { - type args struct { - event func(t *testing.T) eventstore.Event - } - tests := []struct { - name string - args args - reduce func(event eventstore.Event) (*handler.Statement, error) - want wantReduce - }{ - { - name: "org.reduceFeatureSet new", - args: args{ - event: getEvent(testEvent( - repository.EventType(org.FeaturesSetEventType), - org.AggregateType, - []byte(`{ - "tierName": "TierName", - "tierDescription": "TierDescription", - "state": 1, - "stateDescription": "StateDescription", - "auditLogRetention": 1, - "loginPolicyFactors": true, - "loginPolicyIDP": true, - "loginPolicyPasswordless": true, - "loginPolicyRegistration": true, - "loginPolicyUsernameLogin": true, - "loginPolicyPasswordReset": true, - "passwordComplexityPolicy": true, - "labelPolicyPrivateLabel": true, - "labelPolicyWatermark": true, - "customDomain": true, - "privacyPolicy": true, - "metadataUser": true, - "customTextMessage": true, - "customTextLogin": true, - "lockoutPolicy": true, - "actionsAllowed": 1, - "maxActions": 10 - }`), - ), org.FeaturesSetEventMapper), - }, - reduce: (&FeatureProjection{}).reduceFeatureSet, - want: wantReduce{ - aggregateType: eventstore.AggregateType("org"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "UPSERT INTO projections.features (aggregate_id, instance_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed, max_actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - anyArg{}, - uint64(15), - false, - "TierName", - "TierDescription", - domain.FeaturesStateActive, - "StateDescription", - time.Nanosecond, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsMaxAllowed, - 10, - }, - }, - }, - }, - }, - }, - { - name: "org.reduceFeatureSet old", - args: args{ - event: getEvent(testEvent( - repository.EventType(org.FeaturesSetEventType), - org.AggregateType, - []byte(`{ - "tierName": "TierName", - "tierDescription": "TierDescription", - "state": 1, - "stateDescription": "StateDescription", - "auditLogRetention": 1, - "loginPolicyFactors": true, - "loginPolicyIDP": true, - "loginPolicyPasswordless": true, - "loginPolicyRegistration": true, - "loginPolicyUsernameLogin": true, - "loginPolicyPasswordReset": true, - "passwordComplexityPolicy": true, - "labelPolicy": true, - "labelPolicyWatermark": true, - "customDomain": true, - "privacyPolicy": true, - "metadataUser": true, - "customTextMessage": true, - "customTextLogin": true, - "lockoutPolicy": true, - "actions": true - }`), - ), org.FeaturesSetEventMapper), - }, - reduce: (&FeatureProjection{}).reduceFeatureSet, - want: wantReduce{ - aggregateType: eventstore.AggregateType("org"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "UPSERT INTO projections.features (aggregate_id, instance_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - anyArg{}, - uint64(15), - false, - "TierName", - "TierDescription", - domain.FeaturesStateActive, - "StateDescription", - time.Nanosecond, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsAllowedUnlimited, - }, - }, - }, - }, - }, - }, - { - name: "org.reduceFeatureSet required values only", - args: args{ - event: getEvent(testEvent( - repository.EventType(org.FeaturesSetEventType), - org.AggregateType, - []byte(`{}`), - ), org.FeaturesSetEventMapper), - }, - reduce: (&FeatureProjection{}).reduceFeatureSet, - want: wantReduce{ - aggregateType: eventstore.AggregateType("org"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "UPSERT INTO projections.features (aggregate_id, instance_id, change_date, sequence, is_default) VALUES ($1, $2, $3, $4, $5)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - anyArg{}, - uint64(15), - false, - }, - }, - }, - }, - }, - }, - { - name: "org.reduceFeatureRemoved", - reduce: (&FeatureProjection{}).reduceFeatureRemoved, - args: args{ - event: getEvent(testEvent( - repository.EventType(org.FeaturesRemovedEventType), - org.AggregateType, - nil, - ), org.FeaturesRemovedEventMapper), - }, - want: wantReduce{ - aggregateType: eventstore.AggregateType("org"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "DELETE FROM projections.features WHERE (aggregate_id = $1)", - expectedArgs: []interface{}{ - "agg-id", - }, - }, - }, - }, - }, - }, - { - name: "instance.reduceFeatureSet old", - reduce: (&FeatureProjection{}).reduceFeatureSet, - args: args{ - event: getEvent(testEvent( - repository.EventType(instance.FeaturesSetEventType), - instance.AggregateType, - []byte(`{ - "tierName": "TierName", - "tierDescription": "TierDescription", - "state": 1, - "stateDescription": "StateDescription", - "auditLogRetention": 1, - "loginPolicyFactors": true, - "loginPolicyIDP": true, - "loginPolicyPasswordless": true, - "loginPolicyRegistration": true, - "loginPolicyUsernameLogin": true, - "loginPolicyPasswordReset": true, - "passwordComplexityPolicy": true, - "labelPolicy": true, - "labelPolicyWatermark": true, - "customDomain": true, - "privacyPolicy": true, - "metadataUser": true, - "customTextMessage": true, - "customTextLogin": true, - "lockoutPolicy": true, - "actions": true - }`), - ), instance.FeaturesSetEventMapper), - }, - want: wantReduce{ - aggregateType: eventstore.AggregateType("instance"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "UPSERT INTO projections.features (aggregate_id, instance_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - anyArg{}, - uint64(15), - true, - "TierName", - "TierDescription", - domain.FeaturesStateActive, - "StateDescription", - time.Nanosecond, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsAllowedUnlimited, - }, - }, - }, - }, - }, - }, - { - name: "instance.reduceFeatureSet new", - reduce: (&FeatureProjection{}).reduceFeatureSet, - args: args{ - event: getEvent(testEvent( - repository.EventType(instance.FeaturesSetEventType), - instance.AggregateType, - []byte(`{ - "tierName": "TierName", - "tierDescription": "TierDescription", - "state": 1, - "stateDescription": "StateDescription", - "auditLogRetention": 1, - "loginPolicyFactors": true, - "loginPolicyIDP": true, - "loginPolicyPasswordless": true, - "loginPolicyRegistration": true, - "loginPolicyUsernameLogin": true, - "loginPolicyPasswordReset": true, - "passwordComplexityPolicy": true, - "labelPolicyPrivateLabel": true, - "labelPolicyWatermark": true, - "customDomain": true, - "privacyPolicy": true, - "metadataUser": true, - "customTextMessage": true, - "customTextLogin": true, - "lockoutPolicy": true, - "actionsAllowed": 1, - "maxActions": 10 - }`), - ), instance.FeaturesSetEventMapper), - }, - want: wantReduce{ - aggregateType: eventstore.AggregateType("instance"), - sequence: 15, - previousSequence: 10, - projection: FeatureTable, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "UPSERT INTO projections.features (aggregate_id, instance_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed, max_actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - anyArg{}, - uint64(15), - true, - "TierName", - "TierDescription", - domain.FeaturesStateActive, - "StateDescription", - time.Nanosecond, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - domain.ActionsMaxAllowed, - 10, - }, - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - event := baseEvent(t) - got, err := tt.reduce(event) - if !errors.IsErrorInvalidArgument(err) { - t.Errorf("no wrong event mapping: %v, got: %v", err, got) - } - - event = tt.args.event(t) - got, err = tt.reduce(event) - assertReduce(t, got, err, tt.want) - }) - } -} diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go index 872a271a3..ac5246f89 100644 --- a/internal/query/projection/projection.go +++ b/internal/query/projection/projection.go @@ -55,7 +55,6 @@ func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, co NewMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"])) NewMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"])) NewCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"])) - NewFeatureProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["features"])) NewUserProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["users"])) NewLoginNameProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["login_names"])) NewOrgMemberProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["org_members"])) diff --git a/internal/repository/features/features.go b/internal/repository/features/features.go deleted file mode 100644 index 0d67cf8a2..000000000 --- a/internal/repository/features/features.go +++ /dev/null @@ -1,245 +0,0 @@ -package features - -import ( - "encoding/json" - "time" - - "github.com/zitadel/zitadel/internal/domain" - "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/repository" -) - -const ( - featuresPrefix = "features." - FeaturesSetEventType = featuresPrefix + "set" - FeaturesRemovedEventType = featuresPrefix + "removed" -) - -type FeaturesSetEvent struct { - eventstore.BaseEvent `json:"-"` - - TierName *string `json:"tierName,omitempty"` - TierDescription *string `json:"tierDescription,omitempty"` - State *domain.FeaturesState `json:"state,omitempty"` - StateDescription *string `json:"stateDescription,omitempty"` - AuditLogRetention *time.Duration `json:"auditLogRetention,omitempty"` - LoginPolicyFactors *bool `json:"loginPolicyFactors,omitempty"` - LoginPolicyIDP *bool `json:"loginPolicyIDP,omitempty"` - LoginPolicyPasswordless *bool `json:"loginPolicyPasswordless,omitempty"` - LoginPolicyRegistration *bool `json:"loginPolicyRegistration,omitempty"` - LoginPolicyUsernameLogin *bool `json:"loginPolicyUsernameLogin,omitempty"` - LoginPolicyPasswordReset *bool `json:"loginPolicyPasswordReset,omitempty"` - PasswordComplexityPolicy *bool `json:"passwordComplexityPolicy,omitempty"` - LabelPolicy *bool `json:"labelPolicy,omitempty"` - LabelPolicyPrivateLabel *bool `json:"labelPolicyPrivateLabel,omitempty"` - LabelPolicyWatermark *bool `json:"labelPolicyWatermark,omitempty"` - CustomDomain *bool `json:"customDomain,omitempty"` - PrivacyPolicy *bool `json:"privacyPolicy,omitempty"` - MetadataUser *bool `json:"metadataUser,omitempty"` - CustomTextMessage *bool `json:"customTextMessage,omitempty"` - CustomTextLogin *bool `json:"customTextLogin,omitempty"` - LockoutPolicy *bool `json:"lockoutPolicy,omitempty"` - Actions *bool `json:"actions,omitempty"` - ActionsAllowed *domain.ActionsAllowed `json:"actionsAllowed,omitempty"` - MaxActions *int `json:"maxActions,omitempty"` -} - -func (e *FeaturesSetEvent) Data() interface{} { - return e -} - -func (e *FeaturesSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil -} - -func NewFeaturesSetEvent( - base *eventstore.BaseEvent, - changes []FeaturesChanges, -) (*FeaturesSetEvent, error) { - if len(changes) == 0 { - return nil, errors.ThrowPreconditionFailed(nil, "FEATURES-d34F4", "Errors.NoChangesFound") - } - changeEvent := &FeaturesSetEvent{ - BaseEvent: *base, - } - for _, change := range changes { - change(changeEvent) - } - return changeEvent, nil -} - -type FeaturesChanges func(*FeaturesSetEvent) - -func ChangeTierName(tierName string) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.TierName = &tierName - } -} - -func ChangeTierDescription(tierDescription string) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.TierDescription = &tierDescription - } -} - -func ChangeState(State domain.FeaturesState) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.State = &State - } -} - -func ChangeStateDescription(statusDescription string) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.StateDescription = &statusDescription - } -} - -func ChangeAuditLogRetention(retention time.Duration) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.AuditLogRetention = &retention - } -} - -func ChangeLoginPolicyFactors(loginPolicyFactors bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyFactors = &loginPolicyFactors - } -} - -func ChangeLoginPolicyIDP(loginPolicyIDP bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyIDP = &loginPolicyIDP - } -} - -func ChangeLoginPolicyPasswordless(loginPolicyPasswordless bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyPasswordless = &loginPolicyPasswordless - } -} - -func ChangeLoginPolicyRegistration(loginPolicyRegistration bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyRegistration = &loginPolicyRegistration - } -} - -func ChangeLoginPolicyUsernameLogin(loginPolicyUsernameLogin bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyUsernameLogin = &loginPolicyUsernameLogin - } -} - -func ChangeLoginPolicyPasswordReset(loginPolicyPasswordReset bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LoginPolicyPasswordReset = &loginPolicyPasswordReset - } -} - -func ChangePasswordComplexityPolicy(passwordComplexityPolicy bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.PasswordComplexityPolicy = &passwordComplexityPolicy - } -} - -func ChangeLabelPolicyPrivateLabel(labelPolicyPrivateLabel bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LabelPolicyPrivateLabel = &labelPolicyPrivateLabel - } -} - -func ChangeLabelPolicyWatermark(labelPolicyWatermark bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LabelPolicyWatermark = &labelPolicyWatermark - } -} - -func ChangeCustomDomain(customDomain bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.CustomDomain = &customDomain - } -} - -func ChangePrivacyPolicy(privacyPolicy bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.PrivacyPolicy = &privacyPolicy - } -} - -func ChangeMetadataUser(metadataUser bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.MetadataUser = &metadataUser - } -} - -func ChangeCustomTextMessage(customTextMessage bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.CustomTextMessage = &customTextMessage - } -} - -func ChangeCustomTextLogin(customTextLogin bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.CustomTextLogin = &customTextLogin - } -} - -func ChangeLockoutPolicy(lockoutPolicy bool) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.LockoutPolicy = &lockoutPolicy - } -} - -func ChangeActionsAllowed(allowedType domain.ActionsAllowed) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.ActionsAllowed = &allowedType - } -} - -func ChangeMaxActions(maxActions int) func(event *FeaturesSetEvent) { - return func(e *FeaturesSetEvent) { - e.MaxActions = &maxActions - } -} - -func FeaturesSetEventMapper(event *repository.Event) (eventstore.Event, error) { - e := &FeaturesSetEvent{ - BaseEvent: *eventstore.BaseEventFromRepo(event), - } - - err := json.Unmarshal(event.Data, e) - if err != nil { - return nil, errors.ThrowInternal(err, "FEATURES-fdgDg", "unable to unmarshal features") - } - - return e, nil -} - -type FeaturesRemovedEvent struct { - eventstore.BaseEvent `json:"-"` -} - -func (e *FeaturesRemovedEvent) Data() interface{} { - return nil -} - -func (e *FeaturesRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil -} - -func (e *FeaturesRemovedEvent) Assets() []*eventstore.Asset { - return nil -} - -func NewFeaturesRemovedEvent(base *eventstore.BaseEvent) *FeaturesRemovedEvent { - return &FeaturesRemovedEvent{ - BaseEvent: *base, - } -} - -func FeaturesRemovedEventMapper(event *repository.Event) (eventstore.Event, error) { - return &FeaturesRemovedEvent{ - BaseEvent: *eventstore.BaseEventFromRepo(event), - }, nil -} diff --git a/internal/repository/instance/eventstore.go b/internal/repository/instance/eventstore.go index 97a1cb27c..3fe9c4c28 100644 --- a/internal/repository/instance/eventstore.go +++ b/internal/repository/instance/eventstore.go @@ -85,7 +85,6 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(CustomTextSetEventType, CustomTextSetEventMapper). RegisterFilterEventMapper(CustomTextRemovedEventType, CustomTextRemovedEventMapper). RegisterFilterEventMapper(CustomTextTemplateRemovedEventType, CustomTextTemplateRemovedEventMapper). - RegisterFilterEventMapper(FeaturesSetEventType, FeaturesSetEventMapper). RegisterFilterEventMapper(InstanceDomainAddedEventType, DomainAddedEventMapper). RegisterFilterEventMapper(InstanceDomainPrimarySetEventType, DomainPrimarySetEventMapper). RegisterFilterEventMapper(InstanceDomainRemovedEventType, DomainRemovedEventMapper). diff --git a/internal/repository/instance/features.go b/internal/repository/instance/features.go deleted file mode 100644 index 6bd6637c2..000000000 --- a/internal/repository/instance/features.go +++ /dev/null @@ -1,44 +0,0 @@ -package instance - -import ( - "context" - - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/repository" - "github.com/zitadel/zitadel/internal/repository/features" -) - -var ( - FeaturesSetEventType = instanceEventTypePrefix + features.FeaturesSetEventType -) - -type FeaturesSetEvent struct { - features.FeaturesSetEvent -} - -func NewFeaturesSetEvent( - ctx context.Context, - aggregate *eventstore.Aggregate, - changes []features.FeaturesChanges, -) (*FeaturesSetEvent, error) { - changedEvent, err := features.NewFeaturesSetEvent( - eventstore.NewBaseEventForPush( - ctx, - aggregate, - FeaturesSetEventType), - changes, - ) - if err != nil { - return nil, err - } - return &FeaturesSetEvent{FeaturesSetEvent: *changedEvent}, nil -} - -func FeaturesSetEventMapper(event *repository.Event) (eventstore.Event, error) { - e, err := features.FeaturesSetEventMapper(event) - if err != nil { - return nil, err - } - - return &FeaturesSetEvent{FeaturesSetEvent: *e.(*features.FeaturesSetEvent)}, nil -} diff --git a/internal/repository/org/eventstore.go b/internal/repository/org/eventstore.go index e0b479e3c..6b1bd0da5 100644 --- a/internal/repository/org/eventstore.go +++ b/internal/repository/org/eventstore.go @@ -77,8 +77,6 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper). RegisterFilterEventMapper(IDPJWTConfigAddedEventType, IDPJWTConfigAddedEventMapper). RegisterFilterEventMapper(IDPJWTConfigChangedEventType, IDPJWTConfigChangedEventMapper). - RegisterFilterEventMapper(FeaturesSetEventType, FeaturesSetEventMapper). - RegisterFilterEventMapper(FeaturesRemovedEventType, FeaturesRemovedEventMapper). RegisterFilterEventMapper(TriggerActionsSetEventType, TriggerActionsSetEventMapper). RegisterFilterEventMapper(TriggerActionsCascadeRemovedEventType, TriggerActionsCascadeRemovedEventMapper). RegisterFilterEventMapper(FlowClearedEventType, FlowClearedEventMapper) diff --git a/internal/repository/org/features.go b/internal/repository/org/features.go deleted file mode 100644 index 7fbb0c33c..000000000 --- a/internal/repository/org/features.go +++ /dev/null @@ -1,72 +0,0 @@ -package org - -import ( - "context" - - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/repository" - "github.com/zitadel/zitadel/internal/repository/features" -) - -var ( - FeaturesSetEventType = orgEventTypePrefix + features.FeaturesSetEventType - FeaturesRemovedEventType = orgEventTypePrefix + features.FeaturesRemovedEventType -) - -type FeaturesSetEvent struct { - features.FeaturesSetEvent -} - -func NewFeaturesSetEvent( - ctx context.Context, - aggregate *eventstore.Aggregate, - changes []features.FeaturesChanges, -) (*FeaturesSetEvent, error) { - changedEvent, err := features.NewFeaturesSetEvent( - eventstore.NewBaseEventForPush( - ctx, - aggregate, - FeaturesSetEventType), - changes, - ) - if err != nil { - return nil, err - } - return &FeaturesSetEvent{FeaturesSetEvent: *changedEvent}, nil -} - -func FeaturesSetEventMapper(event *repository.Event) (eventstore.Event, error) { - e, err := features.FeaturesSetEventMapper(event) - if err != nil { - return nil, err - } - - return &FeaturesSetEvent{FeaturesSetEvent: *e.(*features.FeaturesSetEvent)}, nil -} - -type FeaturesRemovedEvent struct { - features.FeaturesRemovedEvent -} - -func NewFeaturesRemovedEvent( - ctx context.Context, - aggregate *eventstore.Aggregate, -) *FeaturesRemovedEvent { - return &FeaturesRemovedEvent{ - FeaturesRemovedEvent: *features.NewFeaturesRemovedEvent( - eventstore.NewBaseEventForPush( - ctx, - aggregate, - FeaturesRemovedEventType), - ), - } -} - -func FeaturesRemovedEventMapper(event *repository.Event) (eventstore.Event, error) { - e, err := features.FeaturesRemovedEventMapper(event) - if err != nil { - return nil, err - } - - return &FeaturesRemovedEvent{FeaturesRemovedEvent: *e.(*features.FeaturesRemovedEvent)}, nil -} diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 01a7fb50e..c739420a4 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -379,8 +379,6 @@ Errors: AlreadyExists: Schritt gestartet existiert bereits Done: AlreadyExists: Schritt ausgeführt existiert bereits - Features: - NotChanged: Feature hat nicht geändert CustomText: AlreadyExists: Kundenspezifischer Text existiert bereits Invalid: Kundenspezifischer Text ist ungültig @@ -613,9 +611,6 @@ EventTypes: set: Primäre Domäne gesetzt reserved: Domäne reserviert released: Domäne freigegeben - features: - set: Feature hinzugefügt - removed: Feature entfernt name: reserved: Name der Organisation reserviert released: Name der Organisation freigegeben diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index a905a0610..df4b83772 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -379,8 +379,6 @@ Errors: AlreadyExists: Step started already exists Done: AlreadyExists: Step done already exists - Features: - NotChanged: Feature hat nicht geändert CustomText: AlreadyExists: Custom text already exists Invalid: Custom text invalid @@ -613,9 +611,6 @@ EventTypes: set: Primary domain set reserved: Domain reserved released: Domain released - features: - set: Feature added - removed: Feature removed name: reserved: Organization name reserved released: Organization name released diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 20a927fff..56d5437d2 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -377,8 +377,6 @@ Errors: AlreadyExists: Il passo iniziato già esistente Done: AlreadyExists: Il passo fatto già esistente - Features: - NotChanged: La caratteristica non è cambiata CustomText: AlreadyExists: Il testo personalizzato già esistente Invalid: Testo personalizzato non valido @@ -611,9 +609,6 @@ EventTypes: set: Set di dominio primario reserved: Dominio riservato released: Dominio rilasciato - features: - set: Caratteristica aggiunta - removed: Caratteristica rimossa name: reserved: Nome dell'organizzazione riservato released: Nome dell'organizzazione rilasciata diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index 37e8466e2..a15ca56de 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -10,7 +10,6 @@ import "zitadel/policy.proto"; import "zitadel/settings.proto"; import "zitadel/text.proto"; import "zitadel/member.proto"; -import "zitadel/features.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; @@ -893,58 +892,6 @@ service AdminService { }; } - rpc GetDefaultFeatures(GetDefaultFeaturesRequest) returns (GetDefaultFeaturesResponse) { - option(google.api.http) = { - get: "/features" - }; - - option (zitadel.v1.auth_option) = { - permission: "iam.features.read" - }; - } - - rpc SetDefaultFeatures(SetDefaultFeaturesRequest) returns (SetDefaultFeaturesResponse) { - option(google.api.http) = { - put: "/features" - body: "*" - }; - - option (zitadel.v1.auth_option) = { - permission: "iam.features.write" - }; - } - - rpc GetOrgFeatures(GetOrgFeaturesRequest) returns (GetOrgFeaturesResponse) { - option(google.api.http) = { - get: "/orgs/{org_id}/features" - }; - - option (zitadel.v1.auth_option) = { - permission: "iam.features.read" - }; - } - - rpc SetOrgFeatures(SetOrgFeaturesRequest) returns (SetOrgFeaturesResponse) { - option(google.api.http) = { - put: "/orgs/{org_id}/features" - body: "*" - }; - - option (zitadel.v1.auth_option) = { - permission: "iam.features.write" - }; - } - - rpc ResetOrgFeatures(ResetOrgFeaturesRequest) returns (ResetOrgFeaturesResponse) { - option(google.api.http) = { - delete: "/orgs/{org_id}/features" - }; - - option (zitadel.v1.auth_option) = { - permission: "iam.features.write" - }; - } - //deprecated: please use DomainPolicy instead //Returns the Org IAM policy defined by the administrators of ZITADEL rpc GetOrgIAMPolicy(GetOrgIAMPolicyRequest) returns (GetOrgIAMPolicyResponse) { @@ -3380,92 +3327,6 @@ message UpdateIDPJWTConfigResponse { zitadel.v1.ObjectDetails details = 1; } -message GetDefaultFeaturesRequest {} - -message GetDefaultFeaturesResponse { - zitadel.features.v1.Features features = 1; -} - -message SetDefaultFeaturesRequest { - string tier_name = 1 [(validate.rules).string = {max_len: 200}]; - string description = 2 [(validate.rules).string = {max_len: 200}]; - - google.protobuf.Duration audit_log_retention = 5 [(validate.rules).duration = {gte: {seconds: 0}}]; - bool login_policy_username_login = 6; - bool login_policy_registration = 7; - bool login_policy_idp = 8; - bool login_policy_factors = 9; - bool login_policy_passwordless = 10; - bool password_complexity_policy = 11; - bool label_policy = 12; - bool custom_domain = 13; - bool login_policy_password_reset = 14; - bool label_policy_private_label = 15; - bool label_policy_watermark = 16; - bool custom_text = 17; - bool privacy_policy = 18; - bool metadata_user = 19; - bool custom_text_message = 20; - bool custom_text_login = 21; - bool lockout_policy = 22; - bool actions = 23; - zitadel.features.v1.ActionsAllowed actions_allowed = 24; - int32 max_actions = 25; -} - -message SetDefaultFeaturesResponse { - zitadel.v1.ObjectDetails details = 1; -} - -message GetOrgFeaturesRequest { - string org_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; -} - -message GetOrgFeaturesResponse { - zitadel.features.v1.Features features = 1; -} - -message SetOrgFeaturesRequest { - string org_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; - string tier_name = 2 [(validate.rules).string = {max_len: 200}]; - string description = 3 [(validate.rules).string = {max_len: 200}]; - zitadel.features.v1.FeaturesState state = 4; - string state_description = 5 [(validate.rules).string = {max_len: 200}]; - - google.protobuf.Duration audit_log_retention = 6 [(validate.rules).duration = {gte: {seconds: 0}}]; - bool login_policy_username_login = 7; - bool login_policy_registration = 8; - bool login_policy_idp = 9; - bool login_policy_factors = 10; - bool login_policy_passwordless = 11; - bool password_complexity_policy = 12; - bool label_policy = 13; - bool custom_domain = 14; - bool login_policy_password_reset = 15; - bool label_policy_private_label = 16; - bool label_policy_watermark = 17; - bool custom_text = 18; - bool privacy_policy = 19; - bool metadata_user = 20; - bool custom_text_message = 21; - bool custom_text_login = 22; - bool lockout_policy = 23; - bool actions = 24; - zitadel.features.v1.ActionsAllowed actions_allowed = 25; - int32 max_actions = 26; -} - -message SetOrgFeaturesResponse { - zitadel.v1.ObjectDetails details = 1; -} - -message ResetOrgFeaturesRequest { - string org_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; -} -message ResetOrgFeaturesResponse { - zitadel.v1.ObjectDetails details = 1; -} - message GetOrgIAMPolicyRequest {} message GetOrgIAMPolicyResponse { diff --git a/proto/zitadel/auth.proto b/proto/zitadel/auth.proto index 152da0df8..a9b7a1d5e 100644 --- a/proto/zitadel/auth.proto +++ b/proto/zitadel/auth.proto @@ -551,17 +551,6 @@ service AuthService { }; } - // Returns a list of features, which are allowed on these organisation based on the subscription of the organisation - rpc ListMyZitadelFeatures(ListMyZitadelFeaturesRequest) returns (ListMyZitadelFeaturesResponse) { - option (google.api.http) = { - post: "/features/zitadel/me/_search" - }; - - option (zitadel.v1.auth_option) = { - permission: "authenticated" - }; - } - // Returns the permissions the authorized user has in ZITADEL based on his manager roles (e.g ORG_OWNER) rpc ListMyZitadelPermissions(ListMyZitadelPermissionsRequest) returns (ListMyZitadelPermissionsResponse) { option (google.api.http) = { @@ -1003,13 +992,6 @@ message ListMyProjectOrgsResponse { repeated zitadel.org.v1.Org result = 2; } -//This is an empty request -message ListMyZitadelFeaturesRequest {} - -message ListMyZitadelFeaturesResponse { - repeated string result = 1; -} - //This is an empty request message ListMyZitadelPermissionsRequest {} diff --git a/proto/zitadel/features.proto b/proto/zitadel/features.proto deleted file mode 100644 index 3de7eb80f..000000000 --- a/proto/zitadel/features.proto +++ /dev/null @@ -1,57 +0,0 @@ -syntax = "proto3"; - -import "zitadel/object.proto"; -import "google/protobuf/duration.proto"; - -package zitadel.features.v1; - -option go_package = "github.com/zitadel/zitadel/pkg/grpc/features"; - -message Features { - zitadel.v1.ObjectDetails details = 1; - FeatureTier tier = 2; - bool is_default = 3; - - google.protobuf.Duration audit_log_retention = 4; - bool login_policy_username_login = 5; - bool login_policy_registration = 6; - bool login_policy_idp = 7; - bool login_policy_factors = 8; - bool login_policy_passwordless = 9; - bool password_complexity_policy = 10; - bool label_policy = 11; - bool custom_domain = 12; - bool login_policy_password_reset = 13; - bool label_policy_private_label = 14; - bool label_policy_watermark = 15; - bool custom_text = 16; - bool privacy_policy = 17; - bool metadata_user = 18; - bool custom_text_message = 19; - bool custom_text_login = 20; - bool lockout_policy = 21; - bool actions = 22; - ActionsAllowed actions_allowed = 23; - int32 max_actions = 24; -} - -message FeatureTier { - string name = 1; - string description = 2; - FeaturesState state = 3; - string status_info = 4; -} - - -enum FeaturesState { - FEATURES_STATE_ACTIVE = 0; - FEATURES_STATE_ACTION_REQUIRED = 1; - FEATURES_STATE_CANCELED = 2; - FEATURES_STATE_GRANDFATHERED = 3; -} - -enum ActionsAllowed { - ACTIONS_ALLOWED_NOT_ALLOWED = 0; - ACTIONS_ALLOWED_MAX = 1; - ACTIONS_ALLOWED_UNLIMITED = 2; -} diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index b07ccfb4b..31c9ddead 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -13,7 +13,6 @@ import "zitadel/text.proto"; import "zitadel/message.proto"; import "zitadel/change.proto"; import "zitadel/auth_n_key.proto"; -import "zitadel/features.proto"; import "zitadel/metadata.proto"; import "zitadel/action.proto"; @@ -307,7 +306,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.write" - feature: "metadata.user" }; } @@ -320,7 +318,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.write" - feature: "metadata.user" }; } @@ -333,7 +330,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.read" - feature: "metadata.user" }; } @@ -345,7 +341,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.read" - feature: "metadata.user" }; } @@ -357,7 +352,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.write" - feature: "metadata.user" }; } @@ -370,7 +364,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "user.write" - feature: "metadata.user" }; } @@ -871,7 +864,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.write" - feature: "custom_domain" }; } @@ -895,7 +887,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.write" - feature: "custom_domain" }; } @@ -909,7 +900,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.write" - feature: "custom_domain" }; } @@ -922,7 +912,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.write" - feature: "custom_domain" }; } @@ -1740,16 +1729,6 @@ service ManagementService { }; } - rpc GetFeatures(GetFeaturesRequest) returns (GetFeaturesResponse) { - option (google.api.http) = { - get: "/features" - }; - - option (zitadel.v1.auth_option) = { - permission: "features.read" - }; - } - //deprecated: please use DomainPolicy instead // Returns the domain policy (this policy is managed by the iam administrator) rpc GetOrgIAMPolicy(GetOrgIAMPolicyRequest) returns (GetOrgIAMPolicyResponse) { @@ -1806,7 +1785,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy" }; } @@ -1820,7 +1798,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy" }; } @@ -1858,7 +1835,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.idp" }; } @@ -1870,7 +1846,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.idp" }; } @@ -1894,7 +1869,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.factors" }; } @@ -1906,7 +1880,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.factors" }; } @@ -1930,7 +1903,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.factors" }; } @@ -1942,7 +1914,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "login_policy.factors" }; } @@ -1980,7 +1951,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "password_complexity_policy" }; } @@ -1994,7 +1964,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "password_complexity_policy" }; } @@ -2154,7 +2123,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "privacy_policy" }; } @@ -2169,7 +2137,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "privacy_policy" }; } @@ -2218,7 +2185,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.read" - feature: "label_policy" }; } @@ -2232,7 +2198,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2246,7 +2211,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2260,7 +2224,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2272,7 +2235,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2284,7 +2246,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2296,7 +2257,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2308,7 +2268,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2320,7 +2279,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write" - feature: "label_policy" }; } @@ -2369,7 +2327,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2417,7 +2374,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2466,7 +2422,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2515,7 +2470,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2564,7 +2518,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2613,7 +2566,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.message" }; } @@ -2661,7 +2613,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "policy.write"; - feature: "custom_text.login" }; } @@ -2711,7 +2662,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2724,7 +2674,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2739,7 +2688,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2753,7 +2701,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2766,7 +2713,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2779,7 +2725,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2792,7 +2737,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2805,7 +2749,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.idp.write" - feature: "login_policy.idp" }; } @@ -2817,7 +2760,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.read" - feature: "actions" }; } @@ -2828,7 +2770,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.read" - feature: "actions" }; } @@ -2840,7 +2781,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.write" - feature: "actions" }; } @@ -2852,7 +2792,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.write" - feature: "actions" }; } @@ -2864,7 +2803,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.write" - feature: "actions" }; } @@ -2876,7 +2814,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.write" - feature: "actions" }; } @@ -2888,7 +2825,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.action.delete" - feature: "actions" }; } @@ -2899,7 +2835,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.flow.read" - feature: "actions" }; } @@ -2910,7 +2845,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.flow.delete" - feature: "actions" }; } @@ -2922,7 +2856,6 @@ service ManagementService { option (zitadel.v1.auth_option) = { permission: "org.flow.write" - feature: "actions" }; } } @@ -4378,12 +4311,6 @@ message BulkRemoveUserGrantRequest { message BulkRemoveUserGrantResponse {} -message GetFeaturesRequest {} - -message GetFeaturesResponse { - zitadel.features.v1.Features features = 1; -} - message GetOrgIAMPolicyRequest {} message GetOrgIAMPolicyResponse { diff --git a/proto/zitadel/options.proto b/proto/zitadel/options.proto index b30904e12..b71082858 100644 --- a/proto/zitadel/options.proto +++ b/proto/zitadel/options.proto @@ -14,5 +14,4 @@ extend google.protobuf.MethodOptions { message AuthOption { string permission = 1; string check_field_name = 2; - string feature = 3; } diff --git a/proto/zitadel/settings.proto b/proto/zitadel/settings.proto index b22e1ce8f..02b98a7e9 100644 --- a/proto/zitadel/settings.proto +++ b/proto/zitadel/settings.proto @@ -3,7 +3,6 @@ syntax = "proto3"; import "zitadel/object.proto"; import "validate/validate.proto"; import "google/protobuf/duration.proto"; -import "protoc-gen-openapiv2/options/annotations.proto"; package zitadel.settings.v1; diff --git a/proto/zitadel/system.proto b/proto/zitadel/system.proto index baeefec7e..b18e8b466 100644 --- a/proto/zitadel/system.proto +++ b/proto/zitadel/system.proto @@ -3,14 +3,10 @@ syntax = "proto3"; import "zitadel/object.proto"; import "zitadel/options.proto"; import "zitadel/instance.proto"; -import "zitadel/text.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; -import "google/protobuf/duration.proto"; - import "protoc-gen-openapiv2/options/annotations.proto"; - import "validate/validate.proto"; package zitadel.system.v1;