mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 19:17:32 +00:00
feat: features (#1427)
* features * features * features * fix json tags * add features handler to auth * mocks for tests * add setup step * fixes * add featurelist to auth api * grandfather state and typos * typo * merge new-eventstore * fix login policy tests * label policy in features * audit log retention
This commit is contained in:
@@ -2,26 +2,26 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
|
||||
features_view_model "github.com/caos/zitadel/internal/features/repository/view/model"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
@@ -111,6 +111,68 @@ func (repo *TokenVerifierRepo) ExistsOrg(ctx context.Context, orgID string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
func (repo *TokenVerifierRepo) CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error {
|
||||
features, err := repo.View.FeaturesByAggregateID(orgID)
|
||||
if caos_errs.IsNotFound(err) {
|
||||
return repo.checkDefaultFeatures(ctx, requiredFeatures...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return checkFeatures(features, requiredFeatures...)
|
||||
}
|
||||
|
||||
func checkFeatures(features *features_view_model.FeaturesView, requiredFeatures ...string) error {
|
||||
for _, requiredFeature := range requiredFeatures {
|
||||
if strings.HasPrefix(requiredFeature, domain.FeatureLoginPolicy) {
|
||||
if err := checkLoginPolicyFeatures(features, requiredFeature); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if requiredFeature == domain.FeaturePasswordComplexityPolicy && !features.PasswordComplexityPolicy {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
if requiredFeature == domain.FeatureLabelPolicy && !features.PasswordComplexityPolicy {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLoginPolicyFeatures(features *features_view_model.FeaturesView, 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)
|
||||
}
|
||||
default:
|
||||
if !features.LoginPolicyFactors && !features.LoginPolicyIDP && !features.LoginPolicyPasswordless && !features.LoginPolicyRegistration && !features.LoginPolicyUsernameLogin {
|
||||
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) (_ string, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -150,3 +212,36 @@ func (u *TokenVerifierRepo) getIAMByID(ctx context.Context) (*iam_model.IAM, err
|
||||
}
|
||||
return iam_es_model.IAMToModel(iam), nil
|
||||
}
|
||||
|
||||
func (repo *TokenVerifierRepo) checkDefaultFeatures(ctx context.Context, requiredFeatures ...string) error {
|
||||
features, viewErr := repo.View.FeaturesByAggregateID(domain.IAMID)
|
||||
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
||||
return viewErr
|
||||
}
|
||||
if errors.IsNotFound(viewErr) {
|
||||
features = new(features_view_model.FeaturesView)
|
||||
}
|
||||
events, esErr := repo.getIAMEvents(ctx, features.Sequence)
|
||||
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
||||
return checkFeatures(features, requiredFeatures...)
|
||||
}
|
||||
if esErr != nil {
|
||||
logging.Log("EVENT-PSoc3").WithError(esErr).Debug("error retrieving new events")
|
||||
return esErr
|
||||
}
|
||||
featuresCopy := *features
|
||||
for _, event := range events {
|
||||
if err := featuresCopy.AppendEvent(event); err != nil {
|
||||
return checkFeatures(features, requiredFeatures...)
|
||||
}
|
||||
}
|
||||
return checkFeatures(&featuresCopy, requiredFeatures...)
|
||||
}
|
||||
|
||||
func (repo *TokenVerifierRepo) getIAMEvents(ctx context.Context, sequence uint64) ([]*models.Event, error) {
|
||||
query, err := iam_view.IAMByIDQuery(domain.IAMID, sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.Eventstore.FilterEvents(ctx, query)
|
||||
}
|
||||
|
Reference in New Issue
Block a user