|
|
|
|
@@ -4,6 +4,8 @@ import (
|
|
|
|
|
"context"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
|
|
|
|
|
|
|
|
|
|
"github.com/caos/logging"
|
|
|
|
|
"github.com/caos/zitadel/internal/api/authz"
|
|
|
|
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
|
|
|
|
@@ -32,6 +34,7 @@ type OrgRepository struct {
|
|
|
|
|
SearchLimit uint64
|
|
|
|
|
*org_es.OrgEventstore
|
|
|
|
|
UserEvents *usr_es.UserEventstore
|
|
|
|
|
IAMEventstore *iam_es.IAMEventstore
|
|
|
|
|
View *mgmt_view.View
|
|
|
|
|
Roles []string
|
|
|
|
|
SystemDefaults systemdefaults.SystemDefaults
|
|
|
|
|
@@ -164,7 +167,12 @@ func (repo *OrgRepository) OrgChanges(ctx context.Context, id string, lastSequen
|
|
|
|
|
change.ModifierName = change.ModifierId
|
|
|
|
|
user, _ := repo.UserEvents.UserByID(ctx, change.ModifierId)
|
|
|
|
|
if user != nil {
|
|
|
|
|
change.ModifierName = user.DisplayName
|
|
|
|
|
if user.Human != nil {
|
|
|
|
|
change.ModifierName = user.DisplayName
|
|
|
|
|
}
|
|
|
|
|
if user.Machine != nil {
|
|
|
|
|
change.ModifierName = user.Machine.Name
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return changes, nil
|
|
|
|
|
@@ -328,27 +336,54 @@ func (repo *OrgRepository) ChangeLabelPolicy(ctx context.Context, policy *iam_mo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetLoginPolicy(ctx context.Context) (*iam_model.LoginPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.LoginPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if errors.IsNotFound(err) {
|
|
|
|
|
policy, err = repo.View.LoginPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.LoginPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.LoginPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return repo.GetDefaultLoginPolicy(ctx)
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-38iTr").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), err
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetDefaultLoginPolicy(ctx context.Context) (*iam_model.LoginPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.LoginPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.LoginPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.LoginPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.LoginPolicy.NotFound")
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-28uLp").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), err
|
|
|
|
|
return iam_es_model.LoginPolicyViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
|
|
|
|
|
@@ -426,28 +461,93 @@ func (repo *OrgRepository) RemoveIDPProviderFromIdpProvider(ctx context.Context,
|
|
|
|
|
return sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, nil, aggregates...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if errors.IsNotFound(err) {
|
|
|
|
|
policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
}
|
|
|
|
|
func (repo *OrgRepository) SearchSecondFactors(ctx context.Context) (*iam_model.SecondFactorsSearchResponse, error) {
|
|
|
|
|
policy, err := repo.GetLoginPolicy(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), err
|
|
|
|
|
return &iam_model.SecondFactorsSearchResponse{
|
|
|
|
|
TotalResult: uint64(len(policy.SecondFactors)),
|
|
|
|
|
Result: policy.SecondFactors,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddSecondFactorToLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
|
|
|
|
|
return repo.OrgEventstore.AddSecondFactorToLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, mfa)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) RemoveSecondFactorFromLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) error {
|
|
|
|
|
return repo.OrgEventstore.RemoveSecondFactorFromLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, mfa)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) SearchMultiFactors(ctx context.Context) (*iam_model.MultiFactorsSearchResponse, error) {
|
|
|
|
|
policy, err := repo.GetLoginPolicy(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &iam_model.MultiFactorsSearchResponse{
|
|
|
|
|
TotalResult: uint64(len(policy.MultiFactors)),
|
|
|
|
|
Result: policy.MultiFactors,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddMultiFactorToLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
|
|
|
|
|
return repo.OrgEventstore.AddMultiFactorToLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, mfa)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) RemoveMultiFactorFromLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) error {
|
|
|
|
|
return repo.OrgEventstore.RemoveMultiFactorFromLoginPolicy(ctx, authz.GetCtxData(ctx).OrgID, mfa)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
|
|
|
|
|
policy, viewErr := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordComplexityPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return repo.GetDefaultPasswordComplexityPolicy(ctx)
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-1Bx8s").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordComplexityPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordComplexityPolicy.NotFound")
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-pL9sw").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), err
|
|
|
|
|
return iam_es_model.PasswordComplexityViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
|
|
|
|
|
@@ -468,27 +568,54 @@ func (repo *OrgRepository) RemovePasswordComplexityPolicy(ctx context.Context) e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetPasswordAgePolicy(ctx context.Context) (*iam_model.PasswordAgePolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordAgePolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if errors.IsNotFound(err) {
|
|
|
|
|
policy, err = repo.View.PasswordAgePolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.PasswordAgePolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordAgePolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return repo.GetDefaultPasswordAgePolicy(ctx)
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-5Mx7s").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), err
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetDefaultPasswordAgePolicy(ctx context.Context) (*iam_model.PasswordAgePolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordAgePolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.PasswordAgePolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordAgePolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordAgePolicy.NotFound")
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-3I90s").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), err
|
|
|
|
|
return iam_es_model.PasswordAgeViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddPasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
|
|
|
|
|
@@ -509,27 +636,54 @@ func (repo *OrgRepository) RemovePasswordAgePolicy(ctx context.Context) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetPasswordLockoutPolicy(ctx context.Context) (*iam_model.PasswordLockoutPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordLockoutPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if errors.IsNotFound(err) {
|
|
|
|
|
policy, err = repo.View.PasswordLockoutPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.PasswordLockoutPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordLockoutPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return repo.GetDefaultPasswordLockoutPolicy(ctx)
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-mS9od").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), err
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) GetDefaultPasswordLockoutPolicy(ctx context.Context) (*iam_model.PasswordLockoutPolicyView, error) {
|
|
|
|
|
policy, err := repo.View.PasswordLockoutPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
policy, viewErr := repo.View.PasswordLockoutPolicyByAggregateID(repo.SystemDefaults.IamID)
|
|
|
|
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
|
|
|
|
return nil, viewErr
|
|
|
|
|
}
|
|
|
|
|
if errors.IsNotFound(viewErr) {
|
|
|
|
|
policy = new(iam_es_model.PasswordLockoutPolicyView)
|
|
|
|
|
}
|
|
|
|
|
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
|
|
|
|
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
|
|
|
|
return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordLockoutPolicy.NotFound")
|
|
|
|
|
}
|
|
|
|
|
if esErr != nil {
|
|
|
|
|
logging.Log("EVENT-2Ms9f").WithError(esErr).Debug("error retrieving new events")
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
policyCopy := *policy
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if err := policyCopy.AppendEvent(event); err != nil {
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
policy.Default = true
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), err
|
|
|
|
|
return iam_es_model.PasswordLockoutViewToModel(policy), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (repo *OrgRepository) AddPasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
|
|
|
|
|
|