mirror of
https://github.com/zitadel/zitadel.git
synced 2025-10-19 08:12:53 +00:00
feat: mfa policy (#913)
* feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy on org * feat: add mfa to login policy on org * feat: append events on policy views * feat: iam login policy mfa definition * feat: login policies on orgs * feat: configured mfas in login process * feat: configured mfas in login process * Update internal/ui/login/static/i18n/en.yaml Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: rename software and hardware mfas * fix: pr requests * fix user mfa * fix: test * fix: oidc version * fix: oidc version * fix: proto gen Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -2,6 +2,7 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/logging"
|
||||
@@ -32,6 +33,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
|
||||
@@ -328,27 +330,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 +455,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 +562,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 +630,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) {
|
||||
|
@@ -46,7 +46,11 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case iam_es_model.LoginPolicyAdded, model.LoginPolicyAdded:
|
||||
err = policy.AppendEvent(event)
|
||||
case iam_es_model.LoginPolicyChanged, model.LoginPolicyChanged:
|
||||
case iam_es_model.LoginPolicyChanged, model.LoginPolicyChanged,
|
||||
iam_es_model.LoginPolicySecondFactorAdded, model.LoginPolicySecondFactorAdded,
|
||||
iam_es_model.LoginPolicySecondFactorRemoved, model.LoginPolicySecondFactorRemoved,
|
||||
iam_es_model.LoginPolicyMultiFactorAdded, model.LoginPolicyMultiFactorAdded,
|
||||
iam_es_model.LoginPolicyMultiFactorRemoved, model.LoginPolicyMultiFactorRemoved:
|
||||
policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -85,7 +85,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRe
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, user, view, roles, systemDefaults},
|
||||
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, user, iam, view, roles, systemDefaults},
|
||||
ProjectRepo: eventstore.ProjectRepo{es, conf.SearchLimit, project, usergrant, user, iam, view, roles, systemDefaults.IamID},
|
||||
UserRepo: eventstore.UserRepo{es, conf.SearchLimit, user, org, usergrant, view, systemDefaults},
|
||||
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
|
||||
|
Reference in New Issue
Block a user