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:
Livio Amstutz
2021-03-25 17:26:21 +01:00
committed by GitHub
parent c9b3839f3d
commit a4763b1e4c
97 changed files with 3335 additions and 109 deletions

View File

@@ -0,0 +1,88 @@
package admin
import (
"context"
features_grpc "github.com/caos/zitadel/internal/api/grpc/features"
object_grpc "github.com/caos/zitadel/internal/api/grpc/object"
"github.com/caos/zitadel/internal/domain"
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
)
func (s *Server) GetDefaultFeatures(ctx context.Context, _ *admin_pb.GetDefaultFeaturesRequest) (*admin_pb.GetDefaultFeaturesResponse, error) {
features, err := s.features.GetDefaultFeatures(ctx)
if err != nil {
return nil, err
}
return &admin_pb.GetDefaultFeaturesResponse{
Features: features_grpc.FeaturesFromModel(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.features.GetOrgFeatures(ctx, req.OrgId)
if err != nil {
return nil, err
}
return &admin_pb.GetOrgFeaturesResponse{
Features: features_grpc.FeaturesFromModel(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 {
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,
}
}
func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.Features {
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,
}
}

View File

@@ -1,6 +1,8 @@
package admin
import (
"google.golang.org/grpc"
"github.com/caos/zitadel/internal/admin/repository"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing"
"github.com/caos/zitadel/internal/api/authz"
@@ -8,7 +10,6 @@ import (
"github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/pkg/grpc/admin"
"google.golang.org/grpc"
)
const (
@@ -25,6 +26,7 @@ type Server struct {
iam repository.IAMRepository
administrator repository.AdministratorRepository
repo repository.Repository
features repository.FeaturesRepository
}
type Config struct {
@@ -39,6 +41,7 @@ func CreateServer(command *command.Commands, query *query.Queries, repo reposito
iam: repo,
administrator: repo,
repo: repo,
features: repo,
}
}

View File

@@ -0,0 +1,18 @@
package auth
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
auth_pb "github.com/caos/zitadel/pkg/grpc/auth"
)
func (s *Server) ListMyZitadelFeatures(ctx context.Context, _ *auth_pb.ListMyZitadelFeaturesRequest) (*auth_pb.ListMyZitadelFeaturesResponse, error) {
features, err := s.repo.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &auth_pb.ListMyZitadelFeaturesResponse{
Result: features.FeatureList(),
}, nil
}

View File

@@ -24,7 +24,11 @@ func (s *Server) GetMyUser(ctx context.Context, _ *auth_pb.GetMyUserRequest) (*a
func (s *Server) ListMyUserChanges(ctx context.Context, req *auth_pb.ListMyUserChangesRequest) (*auth_pb.ListMyUserChangesResponse, error) {
offset, limit, asc := object.ListQueryToModel(req.Query)
changes, err := s.repo.MyUserChanges(ctx, offset, limit, asc)
features, err := s.repo.GetOrgFeatures(ctx, authz.GetCtxData(ctx).ResourceOwner)
if err != nil {
return nil, err
}
changes, err := s.repo.MyUserChanges(ctx, offset, limit, asc, features.AuditLogRetention)
if err != nil {
return nil, err
}

View File

@@ -0,0 +1,64 @@
package features
import (
"google.golang.org/protobuf/types/known/durationpb"
object_grpc "github.com/caos/zitadel/internal/api/grpc/object"
"github.com/caos/zitadel/internal/domain"
features_model "github.com/caos/zitadel/internal/features/model"
features_pb "github.com/caos/zitadel/pkg/grpc/features"
)
func FeaturesFromModel(features *features_model.FeaturesView) *features_pb.Features {
return &features_pb.Features{
Details: object_grpc.ToViewDetailsPb(features.Sequence, features.CreationDate, features.ChangeDate, features.AggregateID),
Tier: FeatureTierToPb(features.TierName, features.TierDescription, features.State, features.StateDescription),
IsDefault: features.Default,
AuditLogRetention: durationpb.New(features.AuditLogRetention),
LoginPolicyFactors: features.LoginPolicyFactors,
LoginPolicyIdp: features.LoginPolicyIDP,
LoginPolicyPasswordless: features.LoginPolicyPasswordless,
LoginPolicyRegistration: features.LoginPolicyRegistration,
LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin,
}
}
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
}
}

View File

@@ -0,0 +1,19 @@
package management
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
features_grpc "github.com/caos/zitadel/internal/api/grpc/features"
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
)
func (s *Server) GetFeatures(ctx context.Context, req *mgmt_pb.GetFeaturesRequest) (*mgmt_pb.GetFeaturesResponse, error) {
features, err := s.features.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &mgmt_pb.GetFeaturesResponse{
Features: features_grpc.FeaturesFromModel(features),
}, nil
}

View File

@@ -33,7 +33,11 @@ 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) {
offset, limit, asc := object.ListQueryToModel(req.Query)
response, err := s.org.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, offset, limit, asc)
features, err := s.features.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
response, err := s.org.OrgChanges(ctx, authz.GetCtxData(ctx).OrgID, offset, limit, asc, features.AuditLogRetention)
if err != nil {
return nil, err
}

View File

@@ -73,7 +73,11 @@ func (s *Server) ListGrantedProjects(ctx context.Context, req *mgmt_pb.ListGrant
func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjectChangesRequest) (*mgmt_pb.ListProjectChangesResponse, error) {
offset, limit, asc := object_grpc.ListQueryToModel(req.Query)
res, err := s.project.ProjectChanges(ctx, req.ProjectId, offset, limit, asc)
features, err := s.features.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
res, err := s.project.ProjectChanges(ctx, req.ProjectId, offset, limit, asc, features.AuditLogRetention)
if err != nil {
return nil, err
}

View File

@@ -42,7 +42,11 @@ 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) {
offset, limit, asc := object_grpc.ListQueryToModel(req.Query)
res, err := s.project.ApplicationChanges(ctx, req.ProjectId, req.AppId, offset, limit, asc)
features, err := s.features.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
res, err := s.project.ApplicationChanges(ctx, req.ProjectId, req.AppId, offset, limit, asc, features.AuditLogRetention)
if err != nil {
return nil, err
}

View File

@@ -1,6 +1,8 @@
package management
import (
"google.golang.org/grpc"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/grpc/server"
"github.com/caos/zitadel/internal/command"
@@ -9,7 +11,6 @@ import (
"github.com/caos/zitadel/internal/management/repository/eventsourcing"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/pkg/grpc/management"
"google.golang.org/grpc"
)
const (
@@ -27,6 +28,7 @@ type Server struct {
user repository.UserRepository
usergrant repository.UserGrantRepository
iam repository.IamRepository
features repository.FeaturesRepository
authZ authz.Config
systemDefaults systemdefaults.SystemDefaults
}
@@ -44,6 +46,7 @@ func CreateServer(command *command.Commands, query *query.Queries, repo reposito
user: repo,
usergrant: repo,
iam: repo,
features: repo,
systemDefaults: sd,
}
}

View File

@@ -53,7 +53,11 @@ 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) {
offset, limit, asc := object.ListQueryToModel(req.Query)
res, err := s.user.UserChanges(ctx, req.UserId, offset, limit, asc)
features, err := s.features.GetOrgFeatures(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
res, err := s.user.UserChanges(ctx, req.UserId, offset, limit, asc, features.AuditLogRetention)
if err != nil {
return nil, err
}

View File

@@ -11,7 +11,7 @@ func ModelLoginPolicyToPb(policy *model.LoginPolicyView) *policy_pb.LoginPolicy
IsDefault: policy.Default,
AllowUsernamePassword: policy.AllowUsernamePassword,
AllowRegister: policy.AllowRegister,
AllowExternalIdp: policy.AllowRegister,
AllowExternalIdp: policy.AllowExternalIDP,
ForceMfa: policy.ForceMFA,
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
}

View File

@@ -37,6 +37,9 @@ func (v *verifierMock) ExistsOrg(ctx context.Context, orgID string) error {
func (v *verifierMock) VerifierClientID(ctx context.Context, appName 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 {