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:
Fabi
2020-11-04 11:26:10 +01:00
committed by GitHub
parent 51417be35d
commit 202aae4954
76 changed files with 12913 additions and 5614 deletions

View File

@@ -54,8 +54,8 @@ SystemDefaults:
PasswordCheck: 240h #10d
ExternalLoginCheck: 240h #10d
MfaInitSkip: 720h #30d
MfaSoftwareCheck: 18h
MfaHardwareCheck: 12h
SecondFactorCheck: 18h
MultiFactorCheck: 12h
IamID: 'IAM'
DomainVerification:
VerificationKey:

View File

@@ -2,7 +2,7 @@ import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { BehaviorSubject, Observable } from 'rxjs';
import { MFAState, MfaType, MultiFactor, UserView } from 'src/app/proto/generated/management_pb';
import { MFAState, MfaType, UserMultiFactor, UserView } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -19,13 +19,13 @@ export interface MFAItem {
export class UserMfaComponent implements OnInit, OnDestroy {
public displayedColumns: string[] = ['type', 'state'];
@Input() private user!: UserView.AsObject;
public mfaSubject: BehaviorSubject<MultiFactor.AsObject[]> = new BehaviorSubject<MultiFactor.AsObject[]>([]);
public mfaSubject: BehaviorSubject<UserMultiFactor.AsObject[]> = new BehaviorSubject<UserMultiFactor.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@ViewChild(MatTable) public table!: MatTable<MultiFactor.AsObject>;
@ViewChild(MatTable) public table!: MatTable<UserMultiFactor.AsObject>;
@ViewChild(MatSort) public sort!: MatSort;
public dataSource!: MatTableDataSource<MultiFactor.AsObject>;
public dataSource!: MatTableDataSource<UserMultiFactor.AsObject>;
public MfaType: any = MfaType;
public MFAState: any = MFAState;

View File

@@ -48,7 +48,6 @@ import {
MachineKeySearchResponse,
MachineKeyType,
MachineResponse,
MultiFactors,
NotificationType,
OIDCApplicationCreate,
OIDCConfig,
@@ -142,6 +141,7 @@ import {
UserMembershipSearchQuery,
UserMembershipSearchRequest,
UserMembershipSearchResponse,
UserMultiFactors,
UserPhone,
UserProfile,
UserResponse,
@@ -668,7 +668,7 @@ export class ManagementService {
return this.grpcService.mgmt.getUserProfile(req);
}
public getUserMfas(id: string): Promise<MultiFactors> {
public getUserMfas(id: string): Promise<UserMultiFactors> {
const req = new UserID();
req.setId(id);
return this.grpcService.mgmt.getUserMfas(req);

2
go.sum
View File

@@ -87,6 +87,8 @@ github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
github.com/caos/oidc v0.12.3 h1:bzUg5BdFwRK+Bi7vPHH0pZ3ni/0vMZTNtayRCFPbD4U=
github.com/caos/oidc v0.12.3/go.mod h1:R9UKITZmSo5vNhSLUYcTDH8pAaV2xwPASXg8wpEs2xQ=
github.com/caos/oidc v0.12.4 h1:E6E+LcnVQFHzOSN8GnTfJGgXWiDYtdKu/Xm2+YC/xFk=
github.com/caos/oidc v0.12.4/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=

View File

@@ -2,6 +2,7 @@ package eventstore
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"strings"
"github.com/caos/logging"
@@ -175,11 +176,28 @@ func (repo *IAMRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
}
func (repo *IAMRepository) GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
policy, err := repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
if err != nil {
return nil, err
policy, viewErr := repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
return iam_es_model.LabelPolicyViewToModel(policy), err
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.LabelPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-4bM0s", "Errors.IAM.LabelPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-3M0xs").WithError(esErr).Debug("error retrieving new events")
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
policyCopy := *policy
for _, event := range events {
if err := policyCopy.AppendEvent(event); err != nil {
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
}
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
func (repo *IAMRepository) AddDefaultLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
@@ -193,11 +211,28 @@ func (repo *IAMRepository) ChangeDefaultLabelPolicy(ctx context.Context, policy
}
func (repo *IAMRepository) 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 && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
return iam_es_model.LoginPolicyViewToModel(policy), err
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.LoginPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.LoginPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-2Mi8s").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
}
}
return iam_es_model.LoginPolicyViewToModel(policy), nil
}
func (repo *IAMRepository) AddDefaultLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
@@ -262,11 +297,66 @@ func (repo *IAMRepository) RemoveIDPProviderFromLoginPolicy(ctx context.Context,
return es_sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, nil, aggregates...)
}
func (repo *IAMRepository) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
func (repo *IAMRepository) SearchDefaultSecondFactors(ctx context.Context) (*iam_model.SecondFactorsSearchResponse, error) {
policy, err := repo.GetDefaultLoginPolicy(ctx)
if err != nil {
return nil, err
}
return &iam_model.SecondFactorsSearchResponse{
TotalResult: uint64(len(policy.SecondFactors)),
Result: policy.SecondFactors,
}, nil
}
func (repo *IAMRepository) AddSecondFactorToLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
return repo.IAMEventstore.AddSecondFactorToLoginPolicy(ctx, repo.SystemDefaults.IamID, mfa)
}
func (repo *IAMRepository) RemoveSecondFactorFromLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) error {
return repo.IAMEventstore.RemoveSecondFactorFromLoginPolicy(ctx, repo.SystemDefaults.IamID, mfa)
}
func (repo *IAMRepository) SearchDefaultMultiFactors(ctx context.Context) (*iam_model.MultiFactorsSearchResponse, error) {
policy, err := repo.GetDefaultLoginPolicy(ctx)
if err != nil {
return nil, err
}
return &iam_model.MultiFactorsSearchResponse{
TotalResult: uint64(len(policy.MultiFactors)),
Result: policy.MultiFactors,
}, nil
}
func (repo *IAMRepository) AddMultiFactorToLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
return repo.IAMEventstore.AddMultiFactorToLoginPolicy(ctx, repo.SystemDefaults.IamID, mfa)
}
func (repo *IAMRepository) RemoveMultiFactorFromLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) error {
return repo.IAMEventstore.RemoveMultiFactorFromLoginPolicy(ctx, repo.SystemDefaults.IamID, mfa)
}
func (repo *IAMRepository) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
policy, viewErr := repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.PasswordComplexityPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-1Mc0s", "Errors.IAM.PasswordComplexityPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-3M0xs").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
}
@@ -281,9 +371,26 @@ func (repo *IAMRepository) ChangeDefaultPasswordComplexityPolicy(ctx context.Con
}
func (repo *IAMRepository) 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 && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.PasswordAgePolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-vMyS3", "Errors.IAM.PasswordAgePolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-3M0xs").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
}
}
return iam_es_model.PasswordAgeViewToModel(policy), nil
}
@@ -299,9 +406,26 @@ func (repo *IAMRepository) ChangeDefaultPasswordAgePolicy(ctx context.Context, p
}
func (repo *IAMRepository) 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 && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.PasswordLockoutPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-2M9oP", "Errors.IAM.PasswordLockoutPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-3M0xs").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
}
}
return iam_es_model.PasswordLockoutViewToModel(policy), nil
}
@@ -317,9 +441,26 @@ func (repo *IAMRepository) ChangeDefaultPasswordLockoutPolicy(ctx context.Contex
}
func (repo *IAMRepository) GetOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicyView, error) {
policy, err := repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID)
if err != nil {
return nil, err
policy, viewErr := repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID)
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
return nil, viewErr
}
if caos_errs.IsNotFound(viewErr) {
policy = new(iam_es_model.OrgIAMPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-MkoL0", "Errors.IAM.OrgIAMPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-3M0xs").WithError(esErr).Debug("error retrieving new events")
return iam_es_model.OrgIAMViewToModel(policy), nil
}
policyCopy := *policy
for _, event := range events {
if err := policyCopy.AppendEvent(event); err != nil {
return iam_es_model.OrgIAMViewToModel(policy), nil
}
}
return iam_es_model.OrgIAMViewToModel(policy), nil
}

View File

@@ -45,7 +45,11 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
switch event.Type {
case model.LoginPolicyAdded:
err = policy.AppendEvent(event)
case model.LoginPolicyChanged:
case model.LoginPolicyChanged,
model.LoginPolicySecondFactorAdded,
model.LoginPolicySecondFactorRemoved,
model.LoginPolicyMultiFactorAdded,
model.LoginPolicyMultiFactorRemoved:
policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID)
if err != nil {
return err

View File

@@ -29,6 +29,13 @@ type IAMRepository interface {
SearchDefaultIDPProviders(ctx context.Context, request *iam_model.IDPProviderSearchRequest) (*iam_model.IDPProviderSearchResponse, error)
AddIDPProviderToLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) (*iam_model.IDPProvider, error)
RemoveIDPProviderFromLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) error
SearchDefaultSecondFactors(ctx context.Context) (*iam_model.SecondFactorsSearchResponse, error)
AddSecondFactorToLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error)
RemoveSecondFactorFromLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) error
SearchDefaultMultiFactors(ctx context.Context) (*iam_model.MultiFactorsSearchResponse, error)
AddMultiFactorToLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error)
RemoveMultiFactorFromLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) error
GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
AddDefaultLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error)
ChangeDefaultLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error)

View File

@@ -42,3 +42,45 @@ func (s *Server) RemoveIdpProviderFromDefaultLoginPolicy(ctx context.Context, pr
err := s.iam.RemoveIDPProviderFromLoginPolicy(ctx, idpProviderToModel(provider))
return &empty.Empty{}, err
}
func (s *Server) GetDefaultLoginPolicySecondFactors(ctx context.Context, _ *empty.Empty) (*admin.SecondFactorsResult, error) {
result, err := s.iam.SearchDefaultSecondFactors(ctx)
if err != nil {
return nil, err
}
return secondFactorsResultFromModel(result), nil
}
func (s *Server) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, mfa *admin.SecondFactor) (*admin.SecondFactor, error) {
result, err := s.iam.AddSecondFactorToLoginPolicy(ctx, secondFactorTypeToModel(mfa))
if err != nil {
return nil, err
}
return secondFactorFromModel(result), nil
}
func (s *Server) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, mfa *admin.SecondFactor) (*empty.Empty, error) {
err := s.iam.RemoveSecondFactorFromLoginPolicy(ctx, secondFactorTypeToModel(mfa))
return &empty.Empty{}, err
}
func (s *Server) GetDefaultLoginPolicyMultiFactors(ctx context.Context, _ *empty.Empty) (*admin.MultiFactorsResult, error) {
result, err := s.iam.SearchDefaultMultiFactors(ctx)
if err != nil {
return nil, err
}
return multiFactorResultFromModel(result), nil
}
func (s *Server) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, mfa *admin.MultiFactor) (*admin.MultiFactor, error) {
result, err := s.iam.AddMultiFactorToLoginPolicy(ctx, multiFactorTypeToModel(mfa))
if err != nil {
return nil, err
}
return multiFactorFromModel(result), nil
}
func (s *Server) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, mfa *admin.MultiFactor) (*empty.Empty, error) {
err := s.iam.RemoveMultiFactorFromLoginPolicy(ctx, multiFactorTypeToModel(mfa))
return &empty.Empty{}, err
}

View File

@@ -12,6 +12,7 @@ func loginPolicyToModel(policy *admin.DefaultLoginPolicyRequest) *iam_model.Logi
AllowUsernamePassword: policy.AllowUsernamePassword,
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa,
}
}
@@ -26,6 +27,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *admin.DefaultLoginPoli
AllowUsernamePassword: policy.AllowUsernamePassword,
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA,
CreationDate: creationDate,
ChangeDate: changeDate,
}
@@ -42,6 +44,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *admin.DefaultL
AllowUsernamePassword: policy.AllowUsernamePassword,
AllowExternalIdp: policy.AllowExternalIDP,
AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA,
CreationDate: creationDate,
ChangeDate: changeDate,
}
@@ -103,3 +106,75 @@ func idpConfigTypeToModel(providerType iam_model.IdpConfigType) admin.IdpType {
return admin.IdpType_IDPTYPE_UNSPECIFIED
}
}
func secondFactorsResultFromModel(result *iam_model.SecondFactorsSearchResponse) *admin.SecondFactorsResult {
converted := make([]admin.SecondFactorType, len(result.Result))
for i, mfaType := range result.Result {
converted[i] = secondFactorTypeFromModel(mfaType)
}
return &admin.SecondFactorsResult{
SecondFactors: converted,
}
}
func secondFactorFromModel(mfaType iam_model.SecondFactorType) *admin.SecondFactor {
return &admin.SecondFactor{
SecondFactor: secondFactorTypeFromModel(mfaType),
}
}
func secondFactorTypeFromModel(mfaType iam_model.SecondFactorType) admin.SecondFactorType {
switch mfaType {
case iam_model.SecondFactorTypeOTP:
return admin.SecondFactorType_SECONDFACTORTYPE_OTP
case iam_model.SecondFactorTypeU2F:
return admin.SecondFactorType_SECONDFACTORTYPE_U2F
default:
return admin.SecondFactorType_SECONDFACTORTYPE_UNSPECIFIED
}
}
func secondFactorTypeToModel(mfaType *admin.SecondFactor) iam_model.SecondFactorType {
switch mfaType.SecondFactor {
case admin.SecondFactorType_SECONDFACTORTYPE_OTP:
return iam_model.SecondFactorTypeOTP
case admin.SecondFactorType_SECONDFACTORTYPE_U2F:
return iam_model.SecondFactorTypeU2F
default:
return iam_model.SecondFactorTypeUnspecified
}
}
func multiFactorResultFromModel(result *iam_model.MultiFactorsSearchResponse) *admin.MultiFactorsResult {
converted := make([]admin.MultiFactorType, len(result.Result))
for i, mfaType := range result.Result {
converted[i] = multiFactorTypeFromModel(mfaType)
}
return &admin.MultiFactorsResult{
MultiFactors: converted,
}
}
func multiFactorFromModel(mfaType iam_model.MultiFactorType) *admin.MultiFactor {
return &admin.MultiFactor{
MultiFactor: multiFactorTypeFromModel(mfaType),
}
}
func multiFactorTypeFromModel(mfaType iam_model.MultiFactorType) admin.MultiFactorType {
switch mfaType {
case iam_model.MultiFactorTypeU2FWithPIN:
return admin.MultiFactorType_MULTIFACTORTYPE_U2F_WITH_PIN
default:
return admin.MultiFactorType_MULTIFACTORTYPE_UNSPECIFIED
}
}
func multiFactorTypeToModel(mfaType *admin.MultiFactor) iam_model.MultiFactorType {
switch mfaType.MultiFactor {
case admin.MultiFactorType_MULTIFACTORTYPE_U2F_WITH_PIN:
return iam_model.MultiFactorTypeU2FWithPIN
default:
return iam_model.MultiFactorTypeUnspecified
}
}

View File

@@ -63,3 +63,45 @@ func (s *Server) RemoveIdpProviderFromLoginPolicy(ctx context.Context, provider
err := s.org.RemoveIDPProviderFromLoginPolicy(ctx, idpProviderToModel(provider))
return &empty.Empty{}, err
}
func (s *Server) GetLoginPolicySecondFactors(ctx context.Context, _ *empty.Empty) (*management.SecondFactorsResult, error) {
result, err := s.org.SearchSecondFactors(ctx)
if err != nil {
return nil, err
}
return secondFactorResultFromModel(result), nil
}
func (s *Server) AddSecondFactorToLoginPolicy(ctx context.Context, mfa *management.SecondFactor) (*management.SecondFactor, error) {
result, err := s.org.AddSecondFactorToLoginPolicy(ctx, secondFactorTypeToModel(mfa))
if err != nil {
return nil, err
}
return secondFactorFromModel(result), nil
}
func (s *Server) RemoveSecondFactorFromLoginPolicy(ctx context.Context, mfa *management.SecondFactor) (*empty.Empty, error) {
err := s.org.RemoveSecondFactorFromLoginPolicy(ctx, secondFactorTypeToModel(mfa))
return &empty.Empty{}, err
}
func (s *Server) GetLoginPolicyMultiFactors(ctx context.Context, _ *empty.Empty) (*management.MultiFactorsResult, error) {
result, err := s.org.SearchMultiFactors(ctx)
if err != nil {
return nil, err
}
return multiFactorResultFromModel(result), nil
}
func (s *Server) AddMultiFactorToLoginPolicy(ctx context.Context, mfa *management.MultiFactor) (*management.MultiFactor, error) {
result, err := s.org.AddMultiFactorToLoginPolicy(ctx, multiFactorTypeToModel(mfa))
if err != nil {
return nil, err
}
return multiFactorFromModel(result), nil
}
func (s *Server) RemoveMultiFactorFromLoginPolicy(ctx context.Context, mfa *management.MultiFactor) (*empty.Empty, error) {
err := s.org.RemoveMultiFactorFromLoginPolicy(ctx, multiFactorTypeToModel(mfa))
return &empty.Empty{}, err
}

View File

@@ -12,6 +12,7 @@ func loginPolicyRequestToModel(policy *management.LoginPolicyRequest) *iam_model
AllowUsernamePassword: policy.AllowUsernamePassword,
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa,
}
}
@@ -28,6 +29,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *management.LoginPolicy
AllowRegister: policy.AllowRegister,
CreationDate: creationDate,
ChangeDate: changeDate,
ForceMfa: policy.ForceMFA,
}
}
@@ -45,6 +47,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *management.Log
AllowRegister: policy.AllowRegister,
CreationDate: creationDate,
ChangeDate: changeDate,
ForceMfa: policy.ForceMFA,
}
}
@@ -140,3 +143,75 @@ func idpProviderTypeFromModel(providerType iam_model.IDPProviderType) management
return management.IdpProviderType_IDPPROVIDERTYPE_UNSPECIFIED
}
}
func secondFactorResultFromModel(result *iam_model.SecondFactorsSearchResponse) *management.SecondFactorsResult {
converted := make([]management.SecondFactorType, len(result.Result))
for i, mfaType := range result.Result {
converted[i] = secondFactorTypeFromModel(mfaType)
}
return &management.SecondFactorsResult{
SecondFactors: converted,
}
}
func secondFactorFromModel(mfaType iam_model.SecondFactorType) *management.SecondFactor {
return &management.SecondFactor{
SecondFactor: secondFactorTypeFromModel(mfaType),
}
}
func secondFactorTypeFromModel(mfaType iam_model.SecondFactorType) management.SecondFactorType {
switch mfaType {
case iam_model.SecondFactorTypeOTP:
return management.SecondFactorType_SECONDFACTORTYPE_OTP
case iam_model.SecondFactorTypeU2F:
return management.SecondFactorType_SECONDFACTORTYPE_U2F
default:
return management.SecondFactorType_SECONDFACTORTYPE_UNSPECIFIED
}
}
func secondFactorTypeToModel(mfaType *management.SecondFactor) iam_model.SecondFactorType {
switch mfaType.SecondFactor {
case management.SecondFactorType_SECONDFACTORTYPE_OTP:
return iam_model.SecondFactorTypeOTP
case management.SecondFactorType_SECONDFACTORTYPE_U2F:
return iam_model.SecondFactorTypeU2F
default:
return iam_model.SecondFactorTypeUnspecified
}
}
func multiFactorResultFromModel(result *iam_model.MultiFactorsSearchResponse) *management.MultiFactorsResult {
converted := make([]management.MultiFactorType, len(result.Result))
for i, mfaType := range result.Result {
converted[i] = multiFactorTypeFromModel(mfaType)
}
return &management.MultiFactorsResult{
MultiFactors: converted,
}
}
func multiFactorFromModel(mfaType iam_model.MultiFactorType) *management.MultiFactor {
return &management.MultiFactor{
MultiFactor: multiFactorTypeFromModel(mfaType),
}
}
func multiFactorTypeFromModel(mfaType iam_model.MultiFactorType) management.MultiFactorType {
switch mfaType {
case iam_model.MultiFactorTypeU2FWithPIN:
return management.MultiFactorType_MULTIFACTORTYPE_U2F_WITH_PIN
default:
return management.MultiFactorType_MULTIFACTORTYPE_UNSPECIFIED
}
}
func multiFactorTypeToModel(mfaType *management.MultiFactor) iam_model.MultiFactorType {
switch mfaType.MultiFactor {
case management.MultiFactorType_MULTIFACTORTYPE_U2F_WITH_PIN:
return iam_model.MultiFactorTypeU2FWithPIN
default:
return iam_model.MultiFactorTypeUnspecified
}
}

View File

@@ -208,12 +208,12 @@ func (s *Server) RemoveExternalIDP(ctx context.Context, request *management.Exte
return &empty.Empty{}, err
}
func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.MultiFactors, error) {
func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) {
mfas, err := s.user.UserMfas(ctx, userID.Id)
if err != nil {
return nil, err
}
return &management.MultiFactors{Mfas: mfasFromModel(mfas)}, nil
return &management.UserMultiFactors{Mfas: mfasFromModel(mfas)}, nil
}
func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) {

View File

@@ -491,16 +491,16 @@ func userMembershipViewFromModel(membership *usr_model.UserMembershipView) *mana
}
}
func mfasFromModel(mfas []*usr_model.MultiFactor) []*management.MultiFactor {
converted := make([]*management.MultiFactor, len(mfas))
func mfasFromModel(mfas []*usr_model.MultiFactor) []*management.UserMultiFactor {
converted := make([]*management.UserMultiFactor, len(mfas))
for i, mfa := range mfas {
converted[i] = mfaFromModel(mfa)
}
return converted
}
func mfaFromModel(mfa *usr_model.MultiFactor) *management.MultiFactor {
return &management.MultiFactor{
func mfaFromModel(mfa *usr_model.MultiFactor) *management.UserMultiFactor {
return &management.UserMultiFactor{
State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type),
}

View File

@@ -243,9 +243,9 @@ func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge
}
}
func AMRFromMFAType(mfaType model.MfaType) string {
func AMRFromMFAType(mfaType model.MFAType) string {
switch mfaType {
case model.MfaTypeOTP:
case model.MFATypeOTP:
return amrOTP
default:
return ""

View File

@@ -48,8 +48,8 @@ type AuthRequestRepo struct {
PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration
MfaSoftwareCheckLifeTime time.Duration
MfaHardwareCheckLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
IAMID string
}
@@ -150,6 +150,10 @@ func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string)
if err != nil {
return nil, err
}
err = repo.fillLoginPolicy(ctx, request)
if err != nil {
return nil, err
}
steps, err := repo.nextSteps(ctx, request, true)
if err != nil {
return nil, err
@@ -559,7 +563,11 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
request.AuthTime = userSession.PasswordVerification
}
if step, ok := repo.mfaChecked(userSession, request, user); !ok {
step, ok, err := repo.mfaChecked(userSession, request, user)
if err != nil {
return nil, err
}
if !ok {
return append(steps, step), nil
}
@@ -611,44 +619,48 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
return users, nil
}
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool) {
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) {
mfaLevel := request.MfaLevel()
promptRequired := user.MfaMaxSetUp < mfaLevel
if promptRequired || !repo.mfaSkippedOrSetUp(user) {
promptRequired := (user.MfaMaxSetUp < mfaLevel) || !user.HasRequiredOrgMFALevel(request.LoginPolicy)
if promptRequired || !repo.mfaSkippedOrSetUp(user, request.LoginPolicy) {
types := user.MfaTypesSetupPossible(mfaLevel, request.LoginPolicy)
if promptRequired && len(types) == 0 {
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
}
return &model.MfaPromptStep{
Required: promptRequired,
MfaProviders: user.MfaTypesSetupPossible(mfaLevel),
}, false
MfaProviders: types,
}, false, nil
}
switch mfaLevel {
default:
fallthrough
case model.MfaLevelNotSetUp:
if user.MfaMaxSetUp == model.MfaLevelNotSetUp {
return nil, true
case model.MFALevelNotSetUp:
if user.MfaMaxSetUp == model.MFALevelNotSetUp {
return nil, true, nil
}
fallthrough
case model.MfaLevelSoftware:
if checkVerificationTime(userSession.MfaSoftwareVerification, repo.MfaSoftwareCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.MfaSoftwareVerificationType)
request.AuthTime = userSession.MfaSoftwareVerification
return nil, true
case model.MFALevelSecondFactor:
if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.SecondFactorVerificationType)
request.AuthTime = userSession.SecondFactorVerification
return nil, true, nil
}
fallthrough
case model.MfaLevelHardware:
if checkVerificationTime(userSession.MfaHardwareVerification, repo.MfaHardwareCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.MfaHardwareVerificationType)
request.AuthTime = userSession.MfaHardwareVerification
return nil, true
case model.MFALevelMultiFactor:
if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.MultiFactorVerificationType)
request.AuthTime = userSession.MultiFactorVerification
return nil, true, nil
}
}
return &model.MfaVerificationStep{
MfaProviders: user.MfaTypesAllowed(mfaLevel),
}, false
MfaProviders: user.MfaTypesAllowed(mfaLevel, request.LoginPolicy),
}, false, nil
}
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool {
if user.MfaMaxSetUp > model.MfaLevelNotSetUp {
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, policy *iam_model.LoginPolicyView) bool {
if user.MfaMaxSetUp > model.MFALevelNotSetUp {
return true
}
return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime)

View File

@@ -3,6 +3,8 @@ package eventstore
import (
"context"
"encoding/json"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"testing"
"time"
@@ -46,7 +48,7 @@ func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*user_view_mod
type mockViewUserSession struct {
ExternalLoginVerification time.Time
PasswordVerification time.Time
MfaSoftwareVerification time.Time
SecondFactorVerification time.Time
Users []mockUser
}
@@ -59,7 +61,7 @@ func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model
return &user_view_model.UserSessionView{
ExternalLoginVerification: m.ExternalLoginVerification,
PasswordVerification: m.PasswordVerification,
MfaSoftwareVerification: m.MfaSoftwareVerification,
SecondFactorVerification: m.SecondFactorVerification,
}, nil
}
@@ -116,6 +118,14 @@ type mockViewUser struct {
MfaInitSkipped time.Time
}
type mockLoginPolicy struct {
policy *iam_view_model.LoginPolicyView
}
func (m *mockLoginPolicy) LoginPolicyByAggregateID(id string) (*iam_view_model.LoginPolicyView, error) {
return m.policy, nil
}
func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) {
return &user_view_model.UserView{
State: int32(user_model.UserStateActive),
@@ -186,11 +196,12 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userEventProvider userEventProvider
orgViewProvider orgViewProvider
userGrantProvider userGrantProvider
loginPolicyProvider loginPolicyViewProvider
PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration
MfaSoftwareCheckLifeTime time.Duration
MfaHardwareCheckLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
}
type args struct {
request *model.AuthRequest
@@ -417,15 +428,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"external user (no external verification), external login step",
fields{
userSessionViewProvider: &mockViewUserSession{
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
[]model.NextStep{&model.ExternalLoginStep{}},
@@ -436,19 +447,29 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
fields{
userSessionViewProvider: &mockViewUserSession{
ExternalLoginVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
loginPolicyProvider: &mockLoginPolicy{
policy: &iam_view_model.LoginPolicyView{},
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
args{
&model.AuthRequest{
UserID: "UserID",
SelectedIDPConfigID: "IDPConfigID",
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{},
},
false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -471,21 +492,27 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"external user (no password check needed), callback",
fields{
userSessionViewProvider: &mockViewUserSession{
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
ExternalLoginVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
MfaSoftwareCheckLifeTime: 18 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
args{
&model.AuthRequest{
UserID: "UserID",
SelectedIDPConfigID: "IDPConfigID",
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{},
}, false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -498,16 +525,22 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
OTPState: int32(user_model.MfaStateReady),
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
args{
&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.MfaVerificationStep{
MfaProviders: []model.MfaType{model.MfaTypeOTP},
MfaProviders: []model.MFAType{model.MFATypeOTP},
}},
nil,
},
@@ -521,17 +554,24 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
OTPState: int32(user_model.MfaStateReady),
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
args{
&model.AuthRequest{
UserID: "UserID",
SelectedIDPConfigID: "IDPConfigID",
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.MfaVerificationStep{
MfaProviders: []model.MfaType{model.MfaTypeOTP},
MfaProviders: []model.MFAType{model.MFATypeOTP},
}},
nil,
},
@@ -539,21 +579,27 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"password change required and email verified, password change step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
PasswordChangeRequired: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
args{
&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.ChangePasswordStep{}},
nil,
},
@@ -561,19 +607,24 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"email not verified and no password change required, mail verification step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
args{&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.VerifyEMailStep{}},
nil,
},
@@ -581,20 +632,25 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"email not verified and password change required, mail verification step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
PasswordChangeRequired: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
args{&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.ChangePasswordStep{}, &model.VerifyEMailStep{}},
nil,
},
@@ -602,21 +658,27 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"email verified and no password change required, redirect to callback step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Request: &model.AuthRequestOIDC{}}, false},
args{&model.AuthRequest{
UserID: "UserID",
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -624,21 +686,28 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"prompt none, checkLoggedIn true and authenticated, redirect to callback step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
args{&model.AuthRequest{
UserID: "UserID",
Prompt: model.PromptNone,
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, true},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -646,13 +715,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"prompt none, checkLoggedIn true, authenticated and required user grants missing, grant required step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -660,10 +729,17 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
roleCheck: true,
userGrants: 0,
},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
args{&model.AuthRequest{
UserID: "UserID",
Prompt: model.PromptNone,
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, true},
[]model.NextStep{&model.GrantRequiredStep{}},
nil,
},
@@ -671,13 +747,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"prompt none, checkLoggedIn true, authenticated and required user grants exist, redirect to callback step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -685,10 +761,17 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
roleCheck: true,
userGrants: 2,
},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
PasswordCheckLifeTime: 10 * 24 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
args{&model.AuthRequest{
UserID: "UserID",
Prompt: model.PromptNone,
Request: &model.AuthRequestOIDC{},
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, true},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -696,16 +779,16 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"linking users, password step",
fields{
userSessionViewProvider: &mockViewUserSession{
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MfaSoftwareCheckLifeTime: 18 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{
&model.AuthRequest{
@@ -720,24 +803,27 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
"linking users, linking step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
SecondFactorVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
MfaMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MfaSoftwareCheckLifeTime: 18 * time.Hour,
PasswordCheckLifeTime: 10 * 24 * time.Hour,
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
SecondFactorCheckLifeTime: 18 * time.Hour,
PasswordCheckLifeTime: 10 * 24 * time.Hour,
},
args{
&model.AuthRequest{
UserID: "UserID",
SelectedIDPConfigID: "IDPConfigID",
LinkingUsers: []*model.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
[]model.NextStep{&model.LinkUsersStep{}},
nil,
@@ -754,11 +840,12 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
UserEventProvider: tt.fields.userEventProvider,
OrgViewProvider: tt.fields.orgViewProvider,
UserGrantProvider: tt.fields.userGrantProvider,
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
MfaSoftwareCheckLifeTime: tt.fields.MfaSoftwareCheckLifeTime,
MfaHardwareCheckLifeTime: tt.fields.MfaHardwareCheckLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
}
got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn)
if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) {
@@ -772,14 +859,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
func TestAuthRequestRepo_mfaChecked(t *testing.T) {
type fields struct {
MfaInitSkippedLifeTime time.Duration
MfaSoftwareCheckLifeTime time.Duration
MfaHardwareCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
}
type args struct {
userSession *user_model.UserSessionView
request *model.AuthRequest
user *user_model.UserView
policy *iam_model.LoginPolicyView
}
tests := []struct {
name string
@@ -787,6 +875,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
args args
want model.NextStep
wantChecked bool
errFunc func(err error) bool
}{
//{
// "required, prompt and false", //TODO: enable when LevelsOfAssurance is checked
@@ -799,25 +888,78 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
// },
// false,
//},
{
"not set up, forced by policy, no mfas configured, error",
fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{
ForceMFA: true,
},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp,
},
},
},
nil,
false,
errors.IsPreconditionFailed,
},
{
"not set up, prompt and false",
fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{},
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MfaLevelNotSetUp,
MfaMaxSetUp: model.MFALevelNotSetUp,
},
},
},
&model.MfaPromptStep{
MfaProviders: []model.MfaType{
model.MfaTypeOTP,
MfaProviders: []model.MFAType{
model.MFATypeOTP,
},
},
false,
nil,
},
{
"not set up, forced by org, true",
fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{
ForceMFA: true,
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp,
},
},
},
&model.MfaPromptStep{
Required: true,
MfaProviders: []model.MFAType{
model.MFATypeOTP,
},
},
false,
nil,
},
{
"not set up and skipped, true",
@@ -825,45 +967,55 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{},
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MfaLevelNotSetUp,
MfaMaxSetUp: model.MFALevelNotSetUp,
MfaInitSkipped: time.Now().UTC(),
},
},
},
nil,
true,
nil,
},
{
"checked mfa software, true",
"checked second factor, true",
fields{
MfaSoftwareCheckLifeTime: 18 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{
request: &model.AuthRequest{},
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MfaLevelSoftware,
MfaMaxSetUp: model.MFALevelSecondFactor,
OTPState: user_model.MfaStateReady,
},
},
userSession: &user_model.UserSessionView{MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Hour)},
userSession: &user_model.UserSessionView{SecondFactorVerification: time.Now().UTC().Add(-5 * time.Hour)},
},
nil,
true,
nil,
},
{
"not checked, check and false",
fields{
MfaSoftwareCheckLifeTime: 18 * time.Hour,
SecondFactorCheckLifeTime: 18 * time.Hour,
},
args{
request: &model.AuthRequest{},
request: &model.AuthRequest{
LoginPolicy: &iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MfaLevelSoftware,
MfaMaxSetUp: model.MFALevelSecondFactor,
OTPState: user_model.MfaStateReady,
},
},
@@ -871,19 +1023,24 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
&model.MfaVerificationStep{
MfaProviders: []model.MfaType{model.MfaTypeOTP},
MfaProviders: []model.MFAType{model.MFATypeOTP},
},
false,
nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &AuthRequestRepo{
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
MfaSoftwareCheckLifeTime: tt.fields.MfaSoftwareCheckLifeTime,
MfaHardwareCheckLifeTime: tt.fields.MfaHardwareCheckLifeTime,
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
}
got, ok, err := repo.mfaChecked(tt.args.userSession, tt.args.request, tt.args.user)
if (tt.errFunc != nil && !tt.errFunc(err)) || (err != nil && tt.errFunc == nil) {
t.Errorf("got wrong err: %v ", err)
return
}
got, ok := repo.mfaChecked(tt.args.userSession, tt.args.request, tt.args.user)
if ok != tt.wantChecked {
t.Errorf("mfaChecked() checked = %v, want %v", ok, tt.wantChecked)
}
@@ -897,7 +1054,8 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
MfaInitSkippedLifeTime time.Duration
}
type args struct {
user *user_model.UserView
user *user_model.UserView
policy *iam_model.LoginPolicyView
}
tests := []struct {
name string
@@ -908,11 +1066,16 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
{
"mfa set up, true",
fields{},
args{&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MfaLevelSoftware,
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelSecondFactor,
},
},
}},
&iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
true,
},
{
@@ -920,12 +1083,17 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
},
},
}},
&iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
true,
},
{
@@ -933,12 +1101,17 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
MfaMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
},
},
}},
&iam_model.LoginPolicyView{
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
},
false,
},
}
@@ -947,7 +1120,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
repo := &AuthRequestRepo{
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
}
if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want {
if got := repo.mfaSkippedOrSetUp(tt.args.user, tt.args.policy); got != tt.want {
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)
}
})
@@ -996,9 +1169,9 @@ func Test_userSessionByIDs(t *testing.T) {
eventProvider: &mockEventErrUser{},
},
&user_model.UserSessionView{
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
MfaSoftwareVerification: time.Time{},
MfaHardwareVerification: time.Time{},
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
SecondFactorVerification: time.Time{},
MultiFactorVerification: time.Time{},
},
nil,
},
@@ -1019,9 +1192,9 @@ func Test_userSessionByIDs(t *testing.T) {
},
},
&user_model.UserSessionView{
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
MfaSoftwareVerification: time.Time{},
MfaHardwareVerification: time.Time{},
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
SecondFactorVerification: time.Time{},
MultiFactorVerification: time.Time{},
},
nil,
},
@@ -1046,9 +1219,9 @@ func Test_userSessionByIDs(t *testing.T) {
},
},
&user_model.UserSessionView{
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
MfaSoftwareVerification: time.Time{},
MfaHardwareVerification: time.Time{},
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
SecondFactorVerification: time.Time{},
MultiFactorVerification: time.Time{},
},
nil,
},
@@ -1073,9 +1246,9 @@ func Test_userSessionByIDs(t *testing.T) {
},
},
&user_model.UserSessionView{
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
MfaSoftwareVerification: time.Now().UTC().Round(1 * time.Second),
ChangeDate: time.Now().UTC().Round(1 * time.Second),
PasswordVerification: time.Now().UTC().Round(1 * time.Second),
SecondFactorVerification: time.Now().UTC().Round(1 * time.Second),
ChangeDate: time.Now().UTC().Round(1 * time.Second),
},
nil,
},

View File

@@ -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

View File

@@ -140,8 +140,8 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
MfaInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MfaInitSkip.Duration,
MfaSoftwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaSoftwareCheck.Duration,
MfaHardwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaHardwareCheck.Duration,
SecondFactorCheckLifeTime: systemDefaults.VerificationLifetimes.SecondFactorCheck.Duration,
MultiFactorCheckLifeTime: systemDefaults.VerificationLifetimes.MultiFactorCheck.Duration,
IAMID: systemDefaults.IamID,
},
eventstore.TokenRepo{

View File

@@ -34,7 +34,7 @@ type AuthRequest struct {
LinkingUsers []*ExternalUser
PossibleSteps []NextStep
PasswordVerified bool
MfasVerified []MfaType
MfasVerified []MFAType
Audience []string
AuthTime time.Time
Code string
@@ -109,7 +109,7 @@ func (a *AuthRequest) IsValid() bool {
a.Request != nil && a.Request.IsValid()
}
func (a *AuthRequest) MfaLevel() MfaLevel {
func (a *AuthRequest) MfaLevel() MFALevel {
return -1
//PLANNED: check a.PossibleLOAs (and Prompt Login?)
}

View File

@@ -155,7 +155,7 @@ func TestAuthRequest_MfaLevel(t *testing.T) {
tests := []struct {
name string
fields fields
want MfaLevel
want MFALevel
}{
//PLANNED: Add / replace test cases when LOA is set
{"-1",
@@ -170,7 +170,7 @@ func TestAuthRequest_MfaLevel(t *testing.T) {
PossibleLOAs: tt.fields.PossibleLOAs,
}
if got := a.MfaLevel(); got != tt.want {
t.Errorf("MfaLevel() = %v, want %v", got, tt.want)
t.Errorf("MFALevel() = %v, want %v", got, tt.want)
}
})
}

View File

@@ -107,7 +107,7 @@ func (s *VerifyEMailStep) Type() NextStepType {
type MfaPromptStep struct {
Required bool
MfaProviders []MfaType
MfaProviders []MFAType
}
func (s *MfaPromptStep) Type() NextStepType {
@@ -115,7 +115,7 @@ func (s *MfaPromptStep) Type() NextStepType {
}
type MfaVerificationStep struct {
MfaProviders []MfaType
MfaProviders []MFAType
}
func (s *MfaVerificationStep) Type() NextStepType {
@@ -140,17 +140,18 @@ func (s *RedirectToCallbackStep) Type() NextStepType {
return NextStepRedirectToCallback
}
type MfaType int
type MFAType int
const (
MfaTypeOTP MfaType = iota
MFATypeOTP MFAType = iota
MFATypeU2F
)
type MfaLevel int
type MFALevel int
const (
MfaLevelNotSetUp MfaLevel = iota
MfaLevelSoftware
MfaLevelHardware
MfaLevelHardwareCertified
MFALevelNotSetUp MFALevel = iota
MFALevelSecondFactor
MFALevelMultiFactor
MFALevelMultiFactorCertified
)

View File

@@ -53,8 +53,8 @@ type VerificationLifetimes struct {
PasswordCheck types.Duration
ExternalLoginCheck types.Duration
MfaInitSkip types.Duration
MfaSoftwareCheck types.Duration
MfaHardwareCheck types.Duration
SecondFactorCheck types.Duration
MultiFactorCheck types.Duration
}
type DomainVerification struct {

View File

@@ -13,6 +13,9 @@ type LoginPolicy struct {
AllowRegister bool
AllowExternalIdp bool
IDPProviders []*IDPProvider
ForceMFA bool
SecondFactors []SecondFactorType
MultiFactors []MultiFactorType
}
type IDPProvider struct {
@@ -35,6 +38,21 @@ const (
IDPProviderTypeOrg
)
type SecondFactorType int32
const (
SecondFactorTypeUnspecified SecondFactorType = iota
SecondFactorTypeOTP
SecondFactorTypeU2F
)
type MultiFactorType int32
const (
MultiFactorTypeUnspecified MultiFactorType = iota
MultiFactorTypeU2FWithPIN
)
func (p *LoginPolicy) IsValid() bool {
return p.ObjectRoot.AggregateID != ""
}
@@ -51,3 +69,21 @@ func (p *LoginPolicy) GetIdpProvider(id string) (int, *IDPProvider) {
}
return -1, nil
}
func (p *LoginPolicy) GetSecondFactor(mfaType SecondFactorType) (int, SecondFactorType) {
for i, m := range p.SecondFactors {
if m == mfaType {
return i, m
}
}
return -1, 0
}
func (p *LoginPolicy) GetMultiFactor(mfaType MultiFactorType) (int, MultiFactorType) {
for i, m := range p.MultiFactors {
if m == mfaType {
return i, m
}
}
return -1, 0
}

View File

@@ -10,6 +10,9 @@ type LoginPolicyView struct {
AllowUsernamePassword bool
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
SecondFactors []SecondFactorType
MultiFactors []MultiFactorType
Default bool
CreationDate time.Time
@@ -46,3 +49,17 @@ type LoginPolicySearchResponse struct {
Sequence uint64
Timestamp time.Time
}
func (p *LoginPolicyView) HasSecondFactors() bool {
if p.SecondFactors == nil || len(p.SecondFactors) == 0 {
return false
}
return true
}
func (p *LoginPolicyView) HasMultiFactors() bool {
if p.MultiFactors == nil || len(p.MultiFactors) == 0 {
return false
}
return true
}

View File

@@ -0,0 +1,47 @@
package model
import (
"github.com/caos/zitadel/internal/model"
)
type SecondFactorsSearchRequest struct {
Queries []*MFASearchQuery
}
type MultiFactorsSearchRequest struct {
Offset uint64
Limit uint64
Asc bool
Queries []*MFASearchQuery
}
type MFASearchQuery struct {
Key MFASearchKey
Method model.SearchMethod
Value interface{}
}
type MFASearchKey int32
const (
MFASearchKeyUnspecified MFASearchKey = iota
MFASearchKeyAggregateID
)
type SecondFactorsSearchResponse struct {
TotalResult uint64
Result []SecondFactorType
}
type MultiFactorsSearchResponse struct {
TotalResult uint64
Result []MultiFactorType
}
func (r *SecondFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) {
r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: model.SearchMethodEquals, Value: aggregateID})
}
func (r *MultiFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) {
r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: model.SearchMethodEquals, Value: aggregateID})
}

View File

@@ -9,6 +9,7 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -64,6 +65,14 @@ func (es *IAMEventstore) IAMByID(ctx context.Context, id string) (_ *iam_model.I
return model.IAMToModel(iam), nil
}
func (es *IAMEventstore) IAMEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) {
query, err := IAMByIDQuery(id, sequence)
if err != nil {
return nil, err
}
return es.FilterEvents(ctx, query)
}
func (es *IAMEventstore) StartSetup(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) {
iam, err := es.IAMByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
@@ -484,7 +493,7 @@ func (es *IAMEventstore) ChangeLabelPolicy(ctx context.Context, policy *iam_mode
func (es *IAMEventstore) PrepareAddLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*model.IAM, *models.Aggregate, error) {
if policy == nil || !policy.IsValid() {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.IAM.LoginPolicyInvalid")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-3mP0s", "Errors.IAM.LoginPolicyInvalid")
}
iam, err := es.IAMByID(ctx, policy.AggregateID)
if err != nil {
@@ -516,7 +525,7 @@ func (es *IAMEventstore) AddLoginPolicy(ctx context.Context, policy *iam_model.L
func (es *IAMEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if policy == nil || !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.IAM.LoginPolicyInvalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-3M0so", "Errors.IAM.LoginPolicyInvalid")
}
iam, err := es.IAMByID(ctx, policy.AggregateID)
if err != nil {
@@ -537,7 +546,7 @@ func (es *IAMEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_mode
func (es *IAMEventstore) AddIDPProviderToLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) (*iam_model.IDPProvider, error) {
if provider == nil || !provider.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.IdpProviderInvalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-bMS8i", "Errors.IdpProviderInvalid")
}
iam, err := es.IAMByID(ctx, provider.AggregateID)
if err != nil {
@@ -593,9 +602,107 @@ func (es *IAMEventstore) RemoveIDPProviderFromLoginPolicy(ctx context.Context, p
return nil
}
func (es *IAMEventstore) AddSecondFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
if mfa == iam_model.SecondFactorTypeUnspecified {
return 0, caos_errs.ThrowPreconditionFailed(nil, "EVENT-1M8Js", "Errors.IAM.LoginPolicy.MFA.Unspecified")
}
iam, err := es.IAMByID(ctx, aggregateID)
if err != nil {
return 0, err
}
if _, m := iam.DefaultLoginPolicy.GetSecondFactor(mfa); m != 0 {
return 0, caos_errs.ThrowAlreadyExists(nil, "EVENT-4Rk09", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
repoIam := model.IAMFromModel(iam)
repoMFA := model.SecondFactorFromModel(mfa)
addAggregate := LoginPolicySecondFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, addAggregate)
if err != nil {
return 0, err
}
es.iamCache.cacheIAM(repoIam)
if _, m := model.GetMFA(repoIam.DefaultLoginPolicy.SecondFactors, int32(mfa)); m != 0 {
return iam_model.SecondFactorType(m), nil
}
return 0, caos_errs.ThrowInternal(nil, "EVENT-5N9so", "Errors.Internal")
}
func (es *IAMEventstore) RemoveSecondFactorFromLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.SecondFactorType) error {
if mfa == iam_model.SecondFactorTypeUnspecified {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-4gJ9s", "Errors.IAM.LoginPolicy.MFA.Unspecified")
}
iam, err := es.IAMByID(ctx, aggregateID)
if err != nil {
return err
}
if _, m := iam.DefaultLoginPolicy.GetSecondFactor(mfa); m == 0 {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-gBm9s", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
repoIam := model.IAMFromModel(iam)
repoMFA := model.SecondFactorFromModel(mfa)
removeAgg := LoginPolicySecondFactorRemovedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, removeAgg)
if err != nil {
return err
}
es.iamCache.cacheIAM(repoIam)
return nil
}
func (es *IAMEventstore) AddMultiFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
if mfa == iam_model.MultiFactorTypeUnspecified {
return 0, caos_errs.ThrowPreconditionFailed(nil, "EVENT-2Dh7J", "Errors.IAM.LoginPolicy.MFA.Unspecified")
}
iam, err := es.IAMByID(ctx, aggregateID)
if err != nil {
return 0, err
}
if _, m := iam.DefaultLoginPolicy.GetMultiFactor(mfa); m != 0 {
return 0, caos_errs.ThrowAlreadyExists(nil, "EVENT-4Rk09", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
repoIam := model.IAMFromModel(iam)
repoMFA := model.MultiFactorFromModel(mfa)
addAggregate := LoginPolicyMultiFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, addAggregate)
if err != nil {
return 0, err
}
es.iamCache.cacheIAM(repoIam)
if _, m := model.GetMFA(repoIam.DefaultLoginPolicy.MultiFactors, int32(mfa)); m != 0 {
return iam_model.MultiFactorType(m), nil
}
return 0, caos_errs.ThrowInternal(nil, "EVENT-5N9so", "Errors.Internal")
}
func (es *IAMEventstore) RemoveMultiFactorFromLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) error {
if mfa == iam_model.MultiFactorTypeUnspecified {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-4gJ9s", "Errors.IAM.LoginPolicy.MFA.Unspecified")
}
iam, err := es.IAMByID(ctx, aggregateID)
if err != nil {
return err
}
if _, m := iam.DefaultLoginPolicy.GetMultiFactor(mfa); m == 0 {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-gBm9s", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
repoIam := model.IAMFromModel(iam)
repoMFA := model.MultiFactorFromModel(mfa)
removeAgg := LoginPolicyMultiFactorRemovedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, removeAgg)
if err != nil {
return err
}
es.iamCache.cacheIAM(repoIam)
return nil
}
func (es *IAMEventstore) PrepareAddPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*model.IAM, *models.Aggregate, error) {
if policy == nil {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.IAM.PasswordComplexityPolicy.Empty")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Ks8Fs", "Errors.IAM.PasswordComplexityPolicy.Empty")
}
if err := policy.IsValid(); err != nil {
return nil, nil, err
@@ -764,7 +871,7 @@ func (es *IAMEventstore) GetOrgIAMPolicy(ctx context.Context, iamID string) (*ia
return nil, err
}
if existingIAM.DefaultOrgIAMPolicy == nil {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAM.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting")
}
return existingIAM.DefaultOrgIAMPolicy, nil
}

View File

@@ -2,6 +2,7 @@ package eventsourcing
import (
"encoding/json"
model2 "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/id"
@@ -123,6 +124,25 @@ func GetMockManipulateIAMWithLoginPolicy(ctrl *gomock.Controller) *IAMEventstore
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl *gomock.Controller) *IAMEventstore {
policyData, _ := json.Marshal(model.LoginPolicy{AllowRegister: true, AllowUsernamePassword: true, AllowExternalIdp: true})
idpProviderData, _ := json.Marshal(model.IDPProvider{IDPConfigID: "IDPConfigID", Type: 1})
secondFactor, _ := json.Marshal(model.MFA{MfaType: int32(model2.SecondFactorTypeOTP)})
multiFactor, _ := json.Marshal(model.MFA{MfaType: int32(model2.MultiFactorTypeU2FWithPIN)})
events := []*es_models.Event{
{AggregateID: "AggregateID", Sequence: 1, Type: model.IAMSetupStarted},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyAdded, Data: policyData},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyIDPProviderAdded, Data: idpProviderData},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicySecondFactorAdded, Data: secondFactor},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyMultiFactorAdded, Data: multiFactor},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateIAMWithPasswodComplexityPolicy(ctrl *gomock.Controller) *IAMEventstore {
policyData, _ := json.Marshal(model.PasswordComplexityPolicy{MinLength: 10})
events := []*es_models.Event{

View File

@@ -1657,6 +1657,340 @@ func TestRemoveIdpProviderFromLoginPolicy(t *testing.T) {
}
}
func TestAddSecondFactorToLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IAMEventstore
ctx context.Context
aggreageID string
mfa iam_model.SecondFactorType
}
type res struct {
result iam_model.SecondFactorType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add second factor to login policy, ok",
args: args{
es: GetMockManipulateIAMWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
result: iam_model.SecondFactorTypeOTP,
},
},
{
name: "add second factor to login policy, already existing",
args: args{
es: GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "invalid mfa",
args: args{
es: GetMockManipulateIAM(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
mfa: iam_model.SecondFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockManipulateIAMNotExisting(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "Test",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddSecondFactorToLoginPolicy(tt.args.ctx, tt.args.aggreageID, tt.args.mfa)
if (tt.res.wantErr && !tt.res.errFunc(err)) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if tt.res.wantErr && tt.res.errFunc(err) {
return
}
if result != tt.res.result {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.res.result, result)
}
})
}
}
func TestRemoveSecondFactorFromLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IAMEventstore
ctx context.Context
aggregateID string
mfa iam_model.SecondFactorType
}
type res struct {
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove second factor from login policy, ok",
args: args{
es: GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{},
},
{
name: "remove second factor to login policy, not existing",
args: args{
es: GetMockManipulateIAMWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "invalid provider",
args: args{
es: GetMockManipulateIAM(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockManipulateIAMNotExisting(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.RemoveSecondFactorFromLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if !tt.res.wantErr && err != nil {
t.Errorf("should not get err: %v ", err)
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestAddMultiFactorToLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IAMEventstore
ctx context.Context
aggreageID string
mfa iam_model.MultiFactorType
}
type res struct {
result iam_model.MultiFactorType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add second factor to login policy, ok",
args: args{
es: GetMockManipulateIAMWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
result: iam_model.MultiFactorTypeU2FWithPIN,
},
},
{
name: "add second factor to login policy, already existing",
args: args{
es: GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "invalid mfa",
args: args{
es: GetMockManipulateIAM(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
mfa: iam_model.MultiFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockManipulateIAMNotExisting(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggreageID: "Test",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddMultiFactorToLoginPolicy(tt.args.ctx, tt.args.aggreageID, tt.args.mfa)
if (tt.res.wantErr && !tt.res.errFunc(err)) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if tt.res.wantErr && tt.res.errFunc(err) {
return
}
if result != tt.res.result {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.res.result, result)
}
})
}
}
func TestRemoveMultiFactorFromLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *IAMEventstore
ctx context.Context
aggregateID string
mfa iam_model.MultiFactorType
}
type res struct {
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove second factor from login policy, ok",
args: args{
es: GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{},
},
{
name: "remove second factor to login policy, not existing",
args: args{
es: GetMockManipulateIAMWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "invalid provider",
args: args{
es: GetMockManipulateIAM(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockManipulateIAMNotExisting(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.RemoveMultiFactorFromLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if !tt.res.wantErr && err != nil {
t.Errorf("should not get err: %v ", err)
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestAddLabelPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {

View File

@@ -346,6 +346,70 @@ func LoginPolicyIDPProviderRemovedAggregate(ctx context.Context, aggCreator *es_
return agg.AppendEvent(model.LoginPolicyIDPProviderRemoved, provider)
}
func LoginPolicySecondFactorAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.IAM, mfa *model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-4Gm9s", "Errors.Internal")
}
agg, err := IAMAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.IAMAggregate).
AggregateIDFilter(existing.AggregateID)
validation := checkExistingLoginPolicySecondFactorValidation(mfa.MfaType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicySecondFactorAdded, mfa)
}
}
func LoginPolicySecondFactorRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.IAM, mfa *model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5Bm9s", "Errors.Internal")
}
agg, err := IAMAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.LoginPolicySecondFactorRemoved, mfa)
}
}
func LoginPolicyMultiFactorAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.IAM, mfa *model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-4Gm9s", "Errors.Internal")
}
agg, err := IAMAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.IAMAggregate).
AggregateIDFilter(existing.AggregateID)
validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MfaType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicyMultiFactorAdded, mfa)
}
}
func LoginPolicyMultiFactorRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.IAM, mfa *model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-6Mso9", "Errors.Internal")
}
agg, err := IAMAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.LoginPolicyMultiFactorRemoved, mfa)
}
}
func PasswordComplexityPolicyAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.IAM, policy *model.PasswordComplexityPolicy) (*es_models.Aggregate, error) {
if policy == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Smla8", "Errors.Internal")
@@ -613,3 +677,77 @@ func checkExistingLoginPolicyIDPProviderValidation(idpConfigID string) func(...*
return nil
}
}
func checkExistingLoginPolicySecondFactorValidation(mfaType int32) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
mfas := make([]int32, 0)
for _, event := range events {
switch event.Type {
case model.LoginPolicySecondFactorAdded:
idp := new(model.MFA)
err := idp.SetData(event)
if err != nil {
return err
}
mfas = append(mfas, idp.MfaType)
case model.LoginPolicySecondFactorRemoved:
mfa := new(model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
if mfas[i] == mfa.MfaType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
break
}
}
}
}
for _, m := range mfas {
if m == mfaType {
return errors.ThrowPreconditionFailed(nil, "EVENT-3vmHd", "Errors.IAM.LoginPolicy.MFA.AlreadyExisting")
}
}
return nil
}
}
func checkExistingLoginPolicyMultiFactorValidation(mfaType int32) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
mfas := make([]int32, 0)
for _, event := range events {
switch event.Type {
case model.LoginPolicyMultiFactorAdded:
idp := new(model.MFA)
err := idp.SetData(event)
if err != nil {
return err
}
mfas = append(mfas, idp.MfaType)
case model.LoginPolicyMultiFactorRemoved:
mfa := new(model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
if mfas[i] == mfa.MfaType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
break
}
}
}
}
for _, m := range mfas {
if m == mfaType {
return errors.ThrowPreconditionFailed(nil, "EVENT-6Hsj89", "Errors.IAM.LoginPolicy.MFA.AlreadyExisting")
}
}
return nil
}
}

View File

@@ -1468,6 +1468,360 @@ func TestLoginPolicyIdpProviderRemovedAggregate(t *testing.T) {
}
}
func TestLoginPolicySecondFactorAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existingIAM *model.IAM
newMFA *model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add second factor to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
IAMProjectID: "IAMProjectID",
DefaultLoginPolicy: &model.LoginPolicy{
AllowUsernamePassword: true,
}},
newMFA: &model.MFA{
MfaType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicySecondFactorAdded},
},
},
{
name: "existing iam nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa config nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, IAMProjectID: "IAMProjectID"},
newMFA: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicySecondFactorAddedAggregate(tt.args.aggCreator, tt.args.existingIAM, tt.args.newMFA)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestLoginPolicySecondFactorRemovedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existingIAM *model.IAM
mfa *model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove second factor to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
IAMProjectID: "IAMProjectID",
DefaultLoginPolicy: &model.LoginPolicy{
AllowUsernamePassword: true,
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
},
}},
mfa: &model.MFA{
MfaType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicySecondFactorRemoved},
},
},
{
name: "existing iam nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "idp config config nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, IAMProjectID: "IAMProjectID"},
mfa: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicySecondFactorRemovedAggregate(tt.args.aggCreator, tt.args.existingIAM, tt.args.mfa)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestLoginPolicyMultiFactorAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existingIAM *model.IAM
newMFA *model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add mfa to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
IAMProjectID: "IAMProjectID",
DefaultLoginPolicy: &model.LoginPolicy{
AllowUsernamePassword: true,
}},
newMFA: &model.MFA{
MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicyMultiFactorAdded},
},
},
{
name: "existing iam nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa config nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, IAMProjectID: "IAMProjectID"},
newMFA: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyMultiFactorAddedAggregate(tt.args.aggCreator, tt.args.existingIAM, tt.args.newMFA)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestLoginPolicyMultiFactorRemovedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existingIAM *model.IAM
mfa *model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove mfa to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
IAMProjectID: "IAMProjectID",
DefaultLoginPolicy: &model.LoginPolicy{
AllowUsernamePassword: true,
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
},
}},
mfa: &model.MFA{
MfaType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicyMultiFactorRemoved},
},
},
{
name: "existing iam nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "idp config config nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existingIAM: &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, IAMProjectID: "IAMProjectID"},
mfa: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyMultiFactorRemovedAggregate(tt.args.aggCreator, tt.args.existingIAM, tt.args.mfa)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestPasswordComplexityPolicyAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context

View File

@@ -168,6 +168,14 @@ func (i *IAM) AppendEvent(event *es_models.Event) (err error) {
return i.appendAddIDPProviderToLoginPolicyEvent(event)
case LoginPolicyIDPProviderRemoved:
return i.appendRemoveIDPProviderFromLoginPolicyEvent(event)
case LoginPolicySecondFactorAdded:
return i.appendAddSecondFactorToLoginPolicyEvent(event)
case LoginPolicySecondFactorRemoved:
return i.appendRemoveSecondFactorFromLoginPolicyEvent(event)
case LoginPolicyMultiFactorAdded:
return i.appendAddMultiFactorToLoginPolicyEvent(event)
case LoginPolicyMultiFactorRemoved:
return i.appendRemoveMultiFactorFromLoginPolicyEvent(event)
case LabelPolicyAdded:
return i.appendAddLabelPolicyEvent(event)
case LabelPolicyChanged:

View File

@@ -14,7 +14,10 @@ type LoginPolicy struct {
AllowUsernamePassword bool `json:"allowUsernamePassword"`
AllowRegister bool `json:"allowRegister"`
AllowExternalIdp bool `json:"allowExternalIdp"`
ForceMFA bool `json:"forceMfa"`
IDPProviders []*IDPProvider `json:"-"`
SecondFactors []int32 `json:"-"`
MultiFactors []int32 `json:"-"`
}
type IDPProvider struct {
@@ -27,6 +30,10 @@ type IDPProviderID struct {
IDPConfigID string `json:"idpConfigId"`
}
type MFA struct {
MfaType int32 `json:"mfaType"`
}
func GetIDPProvider(providers []*IDPProvider, id string) (int, *IDPProvider) {
for i, p := range providers {
if p.IDPConfigID == id {
@@ -36,8 +43,18 @@ func GetIDPProvider(providers []*IDPProvider, id string) (int, *IDPProvider) {
return -1, nil
}
func GetMFA(mfas []int32, mfaType int32) (int, int32) {
for i, m := range mfas {
if m == mfaType {
return i, m
}
}
return -1, 0
}
func LoginPolicyToModel(policy *LoginPolicy) *iam_model.LoginPolicy {
idps := IDPProvidersToModel(policy.IDPProviders)
secondFactors := SecondFactorsToModel(policy.SecondFactors)
multiFactors := MultiFactorsToModel(policy.MultiFactors)
return &iam_model.LoginPolicy{
ObjectRoot: policy.ObjectRoot,
State: iam_model.PolicyState(policy.State),
@@ -45,11 +62,16 @@ func LoginPolicyToModel(policy *LoginPolicy) *iam_model.LoginPolicy {
AllowRegister: policy.AllowRegister,
AllowExternalIdp: policy.AllowExternalIdp,
IDPProviders: idps,
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactors,
MultiFactors: multiFactors,
}
}
func LoginPolicyFromModel(policy *iam_model.LoginPolicy) *LoginPolicy {
idps := IDOProvidersFromModel(policy.IDPProviders)
secondFactors := SecondFactorsFromModel(policy.SecondFactors)
multiFactors := MultiFactorsFromModel(policy.MultiFactors)
return &LoginPolicy{
ObjectRoot: policy.ObjectRoot,
State: int32(policy.State),
@@ -57,6 +79,9 @@ func LoginPolicyFromModel(policy *iam_model.LoginPolicy) *LoginPolicy {
AllowRegister: policy.AllowRegister,
AllowExternalIdp: policy.AllowExternalIdp,
IDPProviders: idps,
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactors,
MultiFactors: multiFactors,
}
}
@@ -92,6 +117,46 @@ func IDPProviderFromModel(provider *iam_model.IDPProvider) *IDPProvider {
}
}
func SecondFactorsFromModel(mfas []iam_model.SecondFactorType) []int32 {
convertedMFAs := make([]int32, len(mfas))
for i, mfa := range mfas {
convertedMFAs[i] = int32(mfa)
}
return convertedMFAs
}
func SecondFactorFromModel(mfa iam_model.SecondFactorType) *MFA {
return &MFA{MfaType: int32(mfa)}
}
func SecondFactorsToModel(mfas []int32) []iam_model.SecondFactorType {
convertedMFAs := make([]iam_model.SecondFactorType, len(mfas))
for i, mfa := range mfas {
convertedMFAs[i] = iam_model.SecondFactorType(mfa)
}
return convertedMFAs
}
func MultiFactorsFromModel(mfas []iam_model.MultiFactorType) []int32 {
convertedMFAs := make([]int32, len(mfas))
for i, mfa := range mfas {
convertedMFAs[i] = int32(mfa)
}
return convertedMFAs
}
func MultiFactorFromModel(mfa iam_model.MultiFactorType) *MFA {
return &MFA{MfaType: int32(mfa)}
}
func MultiFactorsToModel(mfas []int32) []iam_model.MultiFactorType {
convertedMFAs := make([]iam_model.MultiFactorType, len(mfas))
for i, mfa := range mfas {
convertedMFAs[i] = iam_model.MultiFactorType(mfa)
}
return convertedMFAs
}
func (p *LoginPolicy) Changes(changed *LoginPolicy) map[string]interface{} {
changes := make(map[string]interface{}, 2)
@@ -104,7 +169,9 @@ func (p *LoginPolicy) Changes(changed *LoginPolicy) map[string]interface{} {
if changed.AllowExternalIdp != p.AllowExternalIdp {
changes["allowExternalIdp"] = changed.AllowExternalIdp
}
if changed.ForceMFA != p.ForceMFA {
changes["forceMFA"] = changed.ForceMFA
}
return changes
}
@@ -143,6 +210,57 @@ func (iam *IAM) appendRemoveIDPProviderFromLoginPolicyEvent(event *es_models.Eve
iam.DefaultLoginPolicy.IDPProviders[i] = iam.DefaultLoginPolicy.IDPProviders[len(iam.DefaultLoginPolicy.IDPProviders)-1]
iam.DefaultLoginPolicy.IDPProviders[len(iam.DefaultLoginPolicy.IDPProviders)-1] = nil
iam.DefaultLoginPolicy.IDPProviders = iam.DefaultLoginPolicy.IDPProviders[:len(iam.DefaultLoginPolicy.IDPProviders)-1]
return nil
}
return nil
}
func (iam *IAM) appendAddSecondFactorToLoginPolicyEvent(event *es_models.Event) error {
mfa := new(MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
iam.DefaultLoginPolicy.SecondFactors = append(iam.DefaultLoginPolicy.SecondFactors, mfa.MfaType)
return nil
}
func (iam *IAM) appendRemoveSecondFactorFromLoginPolicyEvent(event *es_models.Event) error {
mfa := new(MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
if i, m := GetMFA(iam.DefaultLoginPolicy.SecondFactors, mfa.MfaType); m != 0 {
iam.DefaultLoginPolicy.SecondFactors[i] = iam.DefaultLoginPolicy.SecondFactors[len(iam.DefaultLoginPolicy.SecondFactors)-1]
iam.DefaultLoginPolicy.SecondFactors[len(iam.DefaultLoginPolicy.SecondFactors)-1] = 0
iam.DefaultLoginPolicy.SecondFactors = iam.DefaultLoginPolicy.SecondFactors[:len(iam.DefaultLoginPolicy.SecondFactors)-1]
return nil
}
return nil
}
func (iam *IAM) appendAddMultiFactorToLoginPolicyEvent(event *es_models.Event) error {
mfa := new(MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
iam.DefaultLoginPolicy.MultiFactors = append(iam.DefaultLoginPolicy.MultiFactors, mfa.MfaType)
return nil
}
func (iam *IAM) appendRemoveMultiFactorFromLoginPolicyEvent(event *es_models.Event) error {
mfa := new(MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
if i, m := GetMFA(iam.DefaultLoginPolicy.MultiFactors, mfa.MfaType); m != 0 {
iam.DefaultLoginPolicy.MultiFactors[i] = iam.DefaultLoginPolicy.MultiFactors[len(iam.DefaultLoginPolicy.MultiFactors)-1]
iam.DefaultLoginPolicy.MultiFactors[len(iam.DefaultLoginPolicy.MultiFactors)-1] = 0
iam.DefaultLoginPolicy.MultiFactors = iam.DefaultLoginPolicy.MultiFactors[:len(iam.DefaultLoginPolicy.MultiFactors)-1]
return nil
}
return nil
}
@@ -162,3 +280,11 @@ func (p *IDPProvider) SetData(event *es_models.Event) error {
}
return nil
}
func (m *MFA) SetData(event *es_models.Event) error {
err := json.Unmarshal(event.Data, m)
if err != nil {
return errors.ThrowInternal(err, "EVENT-4G9os", "unable to unmarshal data")
}
return nil
}

View File

@@ -23,18 +23,18 @@ func TestLoginPolicyChanges(t *testing.T) {
{
name: "loginpolicy all attributes change",
args: args{
existing: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false},
new: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true},
existing: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false, ForceMFA: false},
new: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true, ForceMFA: true},
},
res: res{
changesLen: 3,
changesLen: 4,
},
},
{
name: "no changes",
args: args{
existing: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false},
new: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false},
existing: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false, ForceMFA: false},
new: &LoginPolicy{AllowUsernamePassword: false, AllowRegister: false, AllowExternalIdp: false, ForceMFA: false},
},
res: res{
changesLen: 0,
@@ -66,10 +66,10 @@ func TestAppendAddLoginPolicyEvent(t *testing.T) {
name: "append add login policy event",
args: args{
iam: new(IAM),
policy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true},
policy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true, ForceMFA: true},
event: new(es_models.Event),
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true}},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true, ForceMFA: true}},
},
}
for _, tt := range tests {
@@ -88,6 +88,9 @@ func TestAppendAddLoginPolicyEvent(t *testing.T) {
if tt.result.DefaultLoginPolicy.AllowExternalIdp != tt.args.iam.DefaultLoginPolicy.AllowExternalIdp {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.AllowExternalIdp, tt.args.iam.DefaultLoginPolicy.AllowExternalIdp)
}
if tt.result.DefaultLoginPolicy.ForceMFA != tt.args.iam.DefaultLoginPolicy.ForceMFA {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.ForceMFA, tt.args.iam.DefaultLoginPolicy.ForceMFA)
}
})
}
}
@@ -110,14 +113,16 @@ func TestAppendChangeLoginPolicyEvent(t *testing.T) {
AllowExternalIdp: false,
AllowRegister: false,
AllowUsernamePassword: false,
ForceMFA: false,
}},
policy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true},
policy: &LoginPolicy{AllowUsernamePassword: true, AllowRegister: true, AllowExternalIdp: true, ForceMFA: true},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
ForceMFA: true,
}},
},
}
@@ -137,6 +142,9 @@ func TestAppendChangeLoginPolicyEvent(t *testing.T) {
if tt.result.DefaultLoginPolicy.AllowExternalIdp != tt.args.iam.DefaultLoginPolicy.AllowExternalIdp {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.AllowExternalIdp, tt.args.iam.DefaultLoginPolicy.AllowExternalIdp)
}
if tt.result.DefaultLoginPolicy.ForceMFA != tt.args.iam.DefaultLoginPolicy.ForceMFA {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.ForceMFA, tt.args.iam.DefaultLoginPolicy.ForceMFA)
}
})
}
}
@@ -197,7 +205,7 @@ func TestAppendAddIdpToPolicyEvent(t *testing.T) {
}
}
func TestRemoveAddIdpToPolicyEvent(t *testing.T) {
func TestRemoveIdpToPolicyEvent(t *testing.T) {
type args struct {
iam *IAM
provider *IDPProvider
@@ -251,3 +259,171 @@ func TestRemoveAddIdpToPolicyEvent(t *testing.T) {
})
}
}
func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
type args struct {
iam *IAM
mfa *MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *IAM
}{
{
name: "append add second factor to login policy event",
args: args{
iam: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
mfa: &MFA{MfaType: int32(model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
SecondFactors: []int32{
int32(model.SecondFactorTypeOTP),
}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.iam.appendAddSecondFactorToLoginPolicyEvent(tt.args.event)
if len(tt.result.DefaultLoginPolicy.SecondFactors) != len(tt.args.iam.DefaultLoginPolicy.SecondFactors) {
t.Errorf("got wrong second factors len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.SecondFactors), len(tt.args.iam.DefaultLoginPolicy.SecondFactors))
}
if tt.result.DefaultLoginPolicy.SecondFactors[0] != tt.args.mfa.MfaType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.SecondFactors[0], tt.args.mfa)
}
})
}
}
func TestRemoveSecondFactorToPolicyEvent(t *testing.T) {
type args struct {
iam *IAM
mfa *MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *IAM
}{
{
name: "append remove second factor to login policy event",
args: args{
iam: &IAM{
DefaultLoginPolicy: &LoginPolicy{
SecondFactors: []int32{
int32(model.SecondFactorTypeOTP),
}}},
mfa: &MFA{MfaType: int32(model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
SecondFactors: []int32{}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.iam.appendRemoveSecondFactorFromLoginPolicyEvent(tt.args.event)
if len(tt.result.DefaultLoginPolicy.SecondFactors) != len(tt.args.iam.DefaultLoginPolicy.SecondFactors) {
t.Errorf("got wrong second factor len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.SecondFactors), len(tt.args.iam.DefaultLoginPolicy.SecondFactors))
}
})
}
}
func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
type args struct {
iam *IAM
mfa *MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *IAM
}{
{
name: "append add mfa to login policy event",
args: args{
iam: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
mfa: &MFA{MfaType: int32(model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
MultiFactors: []int32{
int32(model.MultiFactorTypeU2FWithPIN),
}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.iam.appendAddMultiFactorToLoginPolicyEvent(tt.args.event)
if len(tt.result.DefaultLoginPolicy.MultiFactors) != len(tt.args.iam.DefaultLoginPolicy.MultiFactors) {
t.Errorf("got wrong mfas len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.MultiFactors), len(tt.args.iam.DefaultLoginPolicy.MultiFactors))
}
if tt.result.DefaultLoginPolicy.MultiFactors[0] != tt.args.mfa.MfaType {
t.Errorf("got wrong mfa: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.MultiFactors[0], tt.args.mfa)
}
})
}
}
func TestRemoveMultiFactorToPolicyEvent(t *testing.T) {
type args struct {
iam *IAM
mfa *MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *IAM
}{
{
name: "append remove mfa to login policy event",
args: args{
iam: &IAM{
DefaultLoginPolicy: &LoginPolicy{
MultiFactors: []int32{
int32(model.MultiFactorTypeU2FWithPIN),
}}},
mfa: &MFA{MfaType: int32(model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
MultiFactors: []int32{}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.iam.appendRemoveMultiFactorFromLoginPolicyEvent(tt.args.event)
if len(tt.result.DefaultLoginPolicy.MultiFactors) != len(tt.args.iam.DefaultLoginPolicy.MultiFactors) {
t.Errorf("got wrong mfa len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.MultiFactors), len(tt.args.iam.DefaultLoginPolicy.MultiFactors))
}
})
}
}

View File

@@ -30,8 +30,13 @@ const (
LoginPolicyIDPProviderAdded models.EventType = "iam.policy.login.idpprovider.added"
LoginPolicyIDPProviderRemoved models.EventType = "iam.policy.login.idpprovider.removed"
LoginPolicyIDPProviderCascadeRemoved models.EventType = "iam.policy.login.idpprovider.cascade.removed"
LabelPolicyAdded models.EventType = "iam.policy.label.added"
LabelPolicyChanged models.EventType = "iam.policy.label.changed"
LoginPolicySecondFactorAdded models.EventType = "iam.policy.login.secondfactor.added"
LoginPolicySecondFactorRemoved models.EventType = "iam.policy.login.secondfactor.removed"
LoginPolicyMultiFactorAdded models.EventType = "iam.policy.login.multifactor.added"
LoginPolicyMultiFactorRemoved models.EventType = "iam.policy.login.multifactor.removed"
LabelPolicyAdded models.EventType = "iam.policy.label.added"
LabelPolicyChanged models.EventType = "iam.policy.label.changed"
PasswordComplexityPolicyAdded models.EventType = "iam.policy.password.complexity.added"
PasswordComplexityPolicyChanged models.EventType = "iam.policy.password.complexity.changed"

View File

@@ -3,6 +3,7 @@ package model
import (
"encoding/json"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
"github.com/lib/pq"
"time"
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -23,10 +24,13 @@ type LoginPolicyView struct {
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:login_policy_state"`
AllowRegister bool `json:"allowRegister" gorm:"column:allow_register"`
AllowUsernamePassword bool `json:"allowUsernamePassword" gorm:"column:allow_username_password"`
AllowExternalIDP bool `json:"allowExternalIdp" gorm:"column:allow_external_idp"`
Default bool `json:"-" gorm:"-"`
AllowRegister bool `json:"allowRegister" gorm:"column:allow_register"`
AllowUsernamePassword bool `json:"allowUsernamePassword" gorm:"column:allow_username_password"`
AllowExternalIDP bool `json:"allowExternalIdp" gorm:"column:allow_external_idp"`
ForceMFA bool `json:"forceMFA" gorm:"column:force_mfa"`
SecondFactors pq.Int64Array `json:"-" gorm:"column:second_factors"`
MultiFactors pq.Int64Array `json:"-" gorm:"column:multi_factors"`
Default bool `json:"-" gorm:"-"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
@@ -40,10 +44,29 @@ func LoginPolicyViewFromModel(policy *model.LoginPolicyView) *LoginPolicyView {
AllowRegister: policy.AllowRegister,
AllowExternalIDP: policy.AllowExternalIDP,
AllowUsernamePassword: policy.AllowUsernamePassword,
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactorsFromModel(policy.SecondFactors),
MultiFactors: multiFactorsFromModel(policy.MultiFactors),
Default: policy.Default,
}
}
func secondFactorsFromModel(mfas []model.SecondFactorType) []int64 {
convertedMFAs := make([]int64, len(mfas))
for i, m := range mfas {
convertedMFAs[i] = int64(m)
}
return convertedMFAs
}
func multiFactorsFromModel(mfas []model.MultiFactorType) []int64 {
convertedMFAs := make([]int64, len(mfas))
for i, m := range mfas {
convertedMFAs[i] = int64(m)
}
return convertedMFAs
}
func LoginPolicyViewToModel(policy *LoginPolicyView) *model.LoginPolicyView {
return &model.LoginPolicyView{
AggregateID: policy.AggregateID,
@@ -53,20 +76,57 @@ func LoginPolicyViewToModel(policy *LoginPolicyView) *model.LoginPolicyView {
AllowRegister: policy.AllowRegister,
AllowExternalIDP: policy.AllowExternalIDP,
AllowUsernamePassword: policy.AllowUsernamePassword,
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactorsToModel(policy.SecondFactors),
MultiFactors: multiFactorsToToModel(policy.MultiFactors),
Default: policy.Default,
}
}
func (i *LoginPolicyView) AppendEvent(event *models.Event) (err error) {
i.Sequence = event.Sequence
i.ChangeDate = event.CreationDate
func secondFactorsToModel(mfas []int64) []model.SecondFactorType {
convertedMFAs := make([]model.SecondFactorType, len(mfas))
for i, m := range mfas {
convertedMFAs[i] = model.SecondFactorType(m)
}
return convertedMFAs
}
func multiFactorsToToModel(mfas []int64) []model.MultiFactorType {
convertedMFAs := make([]model.MultiFactorType, len(mfas))
for i, m := range mfas {
convertedMFAs[i] = model.MultiFactorType(m)
}
return convertedMFAs
}
func (p *LoginPolicyView) AppendEvent(event *models.Event) (err error) {
p.Sequence = event.Sequence
p.ChangeDate = event.CreationDate
switch event.Type {
case es_model.LoginPolicyAdded, org_es_model.LoginPolicyAdded:
i.setRootData(event)
i.CreationDate = event.CreationDate
err = i.SetData(event)
p.setRootData(event)
p.CreationDate = event.CreationDate
err = p.SetData(event)
case es_model.LoginPolicyChanged, org_es_model.LoginPolicyChanged:
err = i.SetData(event)
err = p.SetData(event)
case es_model.LoginPolicySecondFactorAdded, org_es_model.LoginPolicySecondFactorAdded:
mfa := new(es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
p.SecondFactors = append(p.SecondFactors, int64(mfa.MfaType))
case es_model.LoginPolicySecondFactorRemoved, org_es_model.LoginPolicySecondFactorRemoved:
err = p.removeSecondFactor(event)
case es_model.LoginPolicyMultiFactorAdded, org_es_model.LoginPolicyMultiFactorAdded:
mfa := new(es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
p.MultiFactors = append(p.MultiFactors, int64(mfa.MfaType))
case es_model.LoginPolicyMultiFactorRemoved, org_es_model.LoginPolicyMultiFactorRemoved:
err = p.removeMultiFactor(event)
}
return err
}
@@ -82,3 +142,37 @@ func (r *LoginPolicyView) SetData(event *models.Event) error {
}
return nil
}
func (p *LoginPolicyView) removeSecondFactor(event *models.Event) error {
mfa := new(es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
for i := len(p.SecondFactors) - 1; i >= 0; i-- {
if p.SecondFactors[i] == int64(mfa.MfaType) {
copy(p.SecondFactors[i:], p.SecondFactors[i+1:])
p.SecondFactors[len(p.SecondFactors)-1] = 0
p.SecondFactors = p.SecondFactors[:len(p.SecondFactors)-1]
return nil
}
}
return nil
}
func (p *LoginPolicyView) removeMultiFactor(event *models.Event) error {
mfa := new(es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
for i := len(p.MultiFactors) - 1; i >= 0; i-- {
if p.MultiFactors[i] == int64(mfa.MfaType) {
copy(p.MultiFactors[i:], p.MultiFactors[i+1:])
p.MultiFactors[len(p.MultiFactors)-1] = 0
p.MultiFactors = p.MultiFactors[:len(p.MultiFactors)-1]
return nil
}
}
return nil
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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},

View File

@@ -49,6 +49,12 @@ type OrgRepository interface {
SearchIDPProviders(ctx context.Context, request *iam_model.IDPProviderSearchRequest) (*iam_model.IDPProviderSearchResponse, error)
AddIDPProviderToLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) (*iam_model.IDPProvider, error)
RemoveIDPProviderFromLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) error
SearchSecondFactors(ctx context.Context) (*iam_model.SecondFactorsSearchResponse, error)
AddSecondFactorToLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error)
RemoveSecondFactorFromLoginPolicy(ctx context.Context, mfa iam_model.SecondFactorType) error
SearchMultiFactors(ctx context.Context) (*iam_model.MultiFactorsSearchResponse, error)
AddMultiFactorToLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error)
RemoveMultiFactorFromLoginPolicy(ctx context.Context, mfa iam_model.MultiFactorType) error
GetPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error)
GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error)

View File

@@ -106,6 +106,14 @@ func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_
return model.OrgToModel(esOrg), nil
}
func (es *OrgEventstore) OrgEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) {
query, err := OrgByIDQuery(id, sequence)
if err != nil {
return nil, err
}
return es.FilterEvents(ctx, query)
}
func (es *OrgEventstore) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
var found bool
err = es_sdk.Filter(ctx, es.FilterEvents, isUniqueValidation(&found), OrgNameUniqueQuery(name))
@@ -767,7 +775,7 @@ func (es *OrgEventstore) AddLoginPolicy(ctx context.Context, policy *iam_model.L
func (es *OrgEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if policy == nil || !policy.IsValid() {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.Org.LoginPolicy.Invalid")
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-mL0ps", "Errors.Org.LoginPolicy.Invalid")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
if err != nil {
@@ -775,7 +783,7 @@ func (es *OrgEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_mode
}
if org.LoginPolicy == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Lso02", "Errors.Org.LoginPolicy.NotExisting")
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-3Mg9s", "Errors.Org.LoginPolicy.NotExisting")
}
repoOrg := model.OrgFromModel(org)
@@ -870,6 +878,96 @@ func (es *OrgEventstore) RemoveIDPProviderFromLoginPolicy(ctx context.Context, p
return es_sdk.PushAggregates(ctx, es.PushAggregates, repoOrg.AppendEvents, agg)
}
func (es *OrgEventstore) AddSecondFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
if mfa == iam_model.SecondFactorTypeUnspecified {
return 0, errors.ThrowPreconditionFailed(nil, "EVENT-3Rf8s", "Errors.Org.LoginPolicy.MFA.Unspecified")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(aggregateID))
if err != nil {
return 0, err
}
if org.LoginPolicy == nil {
return 0, errors.ThrowAlreadyExists(nil, "EVENT-hMd9s", "Errors.Org.LoginPolicy.NotExisting")
}
if _, m := org.LoginPolicy.GetSecondFactor(mfa); m != 0 {
return 0, errors.ThrowAlreadyExists(nil, "EVENT-3Bm9s", "Errors.Org.LoginPolicy.MFA.AlreadyExisting")
}
repoOrg := model.OrgFromModel(org)
repoMFA := iam_es_model.SecondFactorFromModel(mfa)
addAggregate := LoginPolicySecondFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoMFA, es.IamID)
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, addAggregate)
if err != nil {
return 0, err
}
if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.SecondFactors, repoMFA.MfaType); m != 0 {
return iam_model.SecondFactorType(m), nil
}
return 0, errors.ThrowInternal(nil, "EVENT-rM9so", "Errors.Internal")
}
func (es *OrgEventstore) RemoveSecondFactorFromLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.SecondFactorType) error {
if mfa == iam_model.SecondFactorTypeUnspecified {
return errors.ThrowPreconditionFailed(nil, "EVENT-6Nm9s", "Errors.Org.LoginPolicy.MFA.Unspecified")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(aggregateID))
if err != nil {
return err
}
if _, m := org.LoginPolicy.GetSecondFactor(mfa); m == 0 {
return errors.ThrowPreconditionFailed(nil, "EVENT-5Mso9", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
repoOrg := model.OrgFromModel(org)
repoMFA := iam_es_model.SecondFactorFromModel(mfa)
agg := LoginPolicySecondFactorRemovedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoMFA)
return es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, agg)
}
func (es *OrgEventstore) AddMultiFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
if mfa == iam_model.MultiFactorTypeUnspecified {
return 0, errors.ThrowPreconditionFailed(nil, "EVENT-6Zms9", "Errors.Org.LoginPolicy.MFA.Unspecified")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(aggregateID))
if err != nil {
return 0, err
}
if org.LoginPolicy == nil {
return 0, errors.ThrowAlreadyExists(nil, "EVENT-fGmx9", "Errors.Org.LoginPolicy.NotExisting")
}
if _, m := org.LoginPolicy.GetMultiFactor(mfa); m != 0 {
return 0, errors.ThrowAlreadyExists(nil, "EVENT-2Fj9s", "Errors.Org.LoginPolicy.MFA.AlreadyExisting")
}
repoOrg := model.OrgFromModel(org)
repoMFA := iam_es_model.MultiFactorFromModel(mfa)
addAggregate := LoginPolicyMultiFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoMFA, es.IamID)
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, addAggregate)
if err != nil {
return 0, err
}
if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.MultiFactors, repoMFA.MfaType); m != 0 {
return iam_model.MultiFactorType(m), nil
}
return 0, errors.ThrowInternal(nil, "EVENT-2fMo0", "Errors.Internal")
}
func (es *OrgEventstore) RemoveMultiFactorFromLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) error {
if mfa == iam_model.MultiFactorTypeUnspecified {
return errors.ThrowPreconditionFailed(nil, "EVENT-lsM9c", "Errors.Org.LoginPolicy.MFA.Unspecified")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(aggregateID))
if err != nil {
return err
}
if _, m := org.LoginPolicy.GetMultiFactor(mfa); m == 0 {
return errors.ThrowPreconditionFailed(nil, "EVENT-3dM0s", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
repoOrg := model.OrgFromModel(org)
repoMFA := iam_es_model.MultiFactorFromModel(mfa)
agg := LoginPolicyMultiFactorRemovedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoMFA)
return es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, agg)
}
func (es *OrgEventstore) AddPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
if policy == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Sjkl9", "Errors.Org.PasswordComplexityPolicy.Invalid")

View File

@@ -105,6 +105,26 @@ func GetMockChangesOrgWithLoginPolicy(ctrl *gomock.Controller) *OrgEventstore {
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockChangesOrgWithLoginPolicyWithMFA(ctrl *gomock.Controller) *OrgEventstore {
orgData, _ := json.Marshal(model.Org{Name: "MusterOrg"})
loginPolicy, _ := json.Marshal(iam_es_model.LoginPolicy{AllowRegister: true, AllowExternalIdp: true, AllowUsernamePassword: true})
idpData, _ := json.Marshal(iam_es_model.IDPProvider{IDPConfigID: "IDPConfigID", Type: int32(iam_model.IDPProviderTypeSystem)})
secondFactor, _ := json.Marshal(iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)})
multiFactor, _ := json.Marshal(iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)})
events := []*es_models.Event{
{AggregateID: "AggregateID", Sequence: 1, Type: model.OrgAdded, Data: orgData},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyAdded, Data: loginPolicy},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyIDPProviderAdded, Data: idpData},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicySecondFactorAdded, Data: secondFactor},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyMultiFactorAdded, Data: multiFactor},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockChangesOrgWithPasswordComplexityPolicy(ctrl *gomock.Controller) *OrgEventstore {
orgData, _ := json.Marshal(model.Org{Name: "MusterOrg"})
passwordComplexityPolicy, _ := json.Marshal(iam_es_model.PasswordComplexityPolicy{

View File

@@ -2732,6 +2732,344 @@ func TestRemoveIdpProviderFromLoginPolicy(t *testing.T) {
}
}
func TestAddSecondFactorToLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *OrgEventstore
ctx context.Context
aggregateID string
mfa iam_model.SecondFactorType
}
type res struct {
result iam_model.SecondFactorType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add second factor to login policy, ok",
args: args{
es: GetMockChangesOrgWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
result: iam_model.SecondFactorTypeOTP,
},
},
{
name: "add second factor to login policy, already existing",
args: args{
es: GetMockChangesOrgWithLoginPolicyWithMFA(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "invalid mfa",
args: args{
es: GetMockChangesOrgOK(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockChangesOrgNoEvents(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddSecondFactorToLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if (tt.res.wantErr && !tt.res.errFunc(err)) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if tt.res.wantErr && tt.res.errFunc(err) {
return
}
if result != tt.res.result {
t.Errorf("got wrong result : expected: %v, actual: %v ", tt.res.result, result)
}
})
}
}
func TestRemoveSecondFactorFromLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *OrgEventstore
ctx context.Context
aggregateID string
mfa iam_model.SecondFactorType
}
type res struct {
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove second factor from login policy, ok",
args: args{
es: GetMockChangesOrgWithLoginPolicyWithMFA(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{},
},
{
name: "remove second factor from login policy, not existing",
args: args{
es: GetMockChangesOrgWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "invalid provider",
args: args{
es: GetMockChangesOrgOK(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.SecondFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockChangesOrgNoEvents(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.SecondFactorTypeOTP,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.RemoveSecondFactorFromLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if !tt.res.wantErr && err != nil {
t.Errorf("should not get err: %v ", err)
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestAddMultiFactorToLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *OrgEventstore
ctx context.Context
aggregateID string
mfa iam_model.MultiFactorType
}
type res struct {
result iam_model.MultiFactorType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add mfa to login policy, ok",
args: args{
es: GetMockChangesOrgWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
result: iam_model.MultiFactorTypeU2FWithPIN,
},
},
{
name: "add mfa to login policy, already existing",
args: args{
es: GetMockChangesOrgWithLoginPolicyWithMFA(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "invalid mfa",
args: args{
es: GetMockChangesOrgOK(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockChangesOrgNoEvents(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddMultiFactorToLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if (tt.res.wantErr && !tt.res.errFunc(err)) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if tt.res.wantErr && tt.res.errFunc(err) {
return
}
if result != tt.res.result {
t.Errorf("got wrong result : expected: %v, actual: %v ", tt.res.result, result)
}
})
}
}
func TestRemoveMultiFactorFromLoginPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *OrgEventstore
ctx context.Context
aggregateID string
mfa iam_model.MultiFactorType
}
type res struct {
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove mfa from login policy, ok",
args: args{
es: GetMockChangesOrgWithLoginPolicyWithMFA(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{},
},
{
name: "remove mfa from login policy, not existing",
args: args{
es: GetMockChangesOrgWithLoginPolicy(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "invalid provider",
args: args{
es: GetMockChangesOrgOK(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "AggregateID",
mfa: iam_model.MultiFactorTypeUnspecified,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing iam not found",
args: args{
es: GetMockChangesOrgNoEvents(ctrl),
ctx: authz.NewMockContext("orgID", "userID"),
aggregateID: "Test",
mfa: iam_model.MultiFactorTypeU2FWithPIN,
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.RemoveMultiFactorFromLoginPolicy(tt.args.ctx, tt.args.aggregateID, tt.args.mfa)
if !tt.res.wantErr && err != nil {
t.Errorf("should not get err: %v ", err)
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestAddLabelPolicy(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {

View File

@@ -9,18 +9,18 @@ import (
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
func LoginPolicyAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *iam_es_model.LoginPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
func LoginPolicyAddedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, policy *iam_es_model.LoginPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if policy == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Smla8", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.OrgAggregate).
AggregateIDFilter(existing.AggregateID)
AggregateIDFilter(org.AggregateID)
validation := checkExistingLoginPolicyValidation()
agg.SetPrecondition(validationQuery, validation)
@@ -28,16 +28,16 @@ func LoginPolicyAddedAggregate(aggCreator *es_models.AggregateCreator, existing
}
}
func LoginPolicyChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *iam_es_model.LoginPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
func LoginPolicyChangedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, policy *iam_es_model.LoginPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if policy == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Mlco9", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
changes := existing.LoginPolicy.Changes(policy)
changes := org.LoginPolicy.Changes(policy)
if len(changes) == 0 {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Smk8d", "Errors.NoChangesFound")
}
@@ -45,12 +45,12 @@ func LoginPolicyChangedAggregate(aggCreator *es_models.AggregateCreator, existin
}
}
func LoginPolicyRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) {
func LoginPolicyRemovedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if existing == nil {
if org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-S8sio", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
@@ -58,18 +58,18 @@ func LoginPolicyRemovedAggregate(aggCreator *es_models.AggregateCreator, existin
}
}
func LoginPolicyIDPProviderAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, provider *iam_es_model.IDPProvider, iamID string) func(ctx context.Context) (*es_models.Aggregate, error) {
func LoginPolicyIDPProviderAddedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, provider *iam_es_model.IDPProvider, iamID string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if provider == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Sml9d", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
AggregateIDsFilter(existing.AggregateID, iamID)
AggregateIDsFilter(org.AggregateID, iamID)
validation := checkExistingLoginPolicyIDPProviderValidation(provider)
agg.SetPrecondition(validationQuery, validation)
@@ -77,11 +77,11 @@ func LoginPolicyIDPProviderAddedAggregate(aggCreator *es_models.AggregateCreator
}
}
func LoginPolicyIDPProviderRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, provider *iam_es_model.IDPProviderID, cascade bool) (*es_models.Aggregate, error) {
func LoginPolicyIDPProviderRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, org *model.Org, provider *iam_es_model.IDPProviderID, cascade bool) (*es_models.Aggregate, error) {
if provider == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Sml9d", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
@@ -92,6 +92,71 @@ func LoginPolicyIDPProviderRemovedAggregate(ctx context.Context, aggCreator *es_
return agg.AppendEvent(eventType, provider)
}
func LoginPolicySecondFactorAddedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, mfa *iam_es_model.MFA, iamID string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5Gk9s", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.OrgAggregate).
AggregateIDsFilter(org.AggregateID)
validation := checkExistingLoginPolicySecondFactorValidation(mfa.MfaType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicySecondFactorAdded, mfa)
}
}
func LoginPolicySecondFactorRemovedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, mfa *iam_es_model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Sml9d", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.LoginPolicySecondFactorRemoved, mfa)
}
}
func LoginPolicyMultiFactorAddedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, mfa *iam_es_model.MFA, iamID string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-4Bm9s", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.OrgAggregate).
AggregateIDsFilter(org.AggregateID)
validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MfaType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicyMultiFactorAdded, mfa)
}
}
func LoginPolicyMultiFactorRemovedAggregate(aggCreator *es_models.AggregateCreator, org *model.Org, mfa *iam_es_model.MFA) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if mfa == nil || org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-6Nm9s", "Errors.Internal")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.LoginPolicyMultiFactorRemoved, mfa)
}
}
func checkExistingLoginPolicyValidation() func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
existing := false
@@ -184,3 +249,83 @@ func checkExistingLoginPolicyIDPProviderValidation(idpProvider *iam_es_model.IDP
return nil
}
}
func checkExistingLoginPolicySecondFactorValidation(mfaType int32) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
mfas := make([]int32, 0)
for _, event := range events {
switch event.Type {
case model.LoginPolicySecondFactorAdded:
mfa := new(iam_es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
mfas = append(mfas, mfa.MfaType)
case model.LoginPolicySecondFactorRemoved:
idp := new(iam_es_model.IDPProvider)
err := idp.SetData(event)
if err != nil {
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
if mfas[i] == mfaType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
break
}
}
case model.LoginPolicyRemoved:
mfas = make([]int32, 0)
}
}
for _, m := range mfas {
if m == mfaType {
return errors.ThrowPreconditionFailed(nil, "EVENT-4Bo0sw", "Errors.Org.LoginPolicy.MFA.AlreadyExisting")
}
}
return nil
}
}
func checkExistingLoginPolicyMultiFactorValidation(mfaType int32) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
mfas := make([]int32, 0)
for _, event := range events {
switch event.Type {
case model.LoginPolicyMultiFactorAdded:
mfa := new(iam_es_model.MFA)
err := mfa.SetData(event)
if err != nil {
return err
}
mfas = append(mfas, mfa.MfaType)
case model.LoginPolicyMultiFactorRemoved:
idp := new(iam_es_model.IDPProvider)
err := idp.SetData(event)
if err != nil {
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
if mfas[i] == mfaType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
break
}
}
case model.LoginPolicyRemoved:
mfas = make([]int32, 0)
}
}
for _, m := range mfas {
if m == mfaType {
return errors.ThrowPreconditionFailed(nil, "EVENT-4Bo0sw", "Errors.Org.LoginPolicy.MFA.AlreadyExisting")
}
}
return nil
}
}

View File

@@ -76,7 +76,10 @@ func TestLoginPolicyAddedAggregate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
@@ -88,10 +91,6 @@ func TestLoginPolicyAddedAggregate(t *testing.T) {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
@@ -165,7 +164,10 @@ func TestLoginPolicyChangedAggregate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
@@ -177,10 +179,6 @@ func TestLoginPolicyChangedAggregate(t *testing.T) {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
@@ -235,7 +233,10 @@ func TestLoginPolicyRemovedAggregate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyRemovedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
@@ -244,10 +245,6 @@ func TestLoginPolicyRemovedAggregate(t *testing.T) {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
@@ -318,7 +315,10 @@ func TestLoginPolicyIdpProviderAddedAggregate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyIDPProviderAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "IAMID")(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
@@ -330,10 +330,6 @@ func TestLoginPolicyIdpProviderAddedAggregate(t *testing.T) {
t.Errorf("should have data in event")
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
@@ -431,7 +427,10 @@ func TestLoginPolicyIdpProviderRemovedAggregate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyIDPProviderRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new, tt.args.cascade)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
@@ -443,9 +442,351 @@ func TestLoginPolicyIdpProviderRemovedAggregate(t *testing.T) {
t.Errorf("should have data in event")
}
}
})
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
func TestLoginPolicySecondFactorAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Org
new *iam_es_model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add second factor to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
},
new: &iam_es_model.MFA{
MfaType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicySecondFactorAdded},
},
},
{
name: "existing org nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicySecondFactorAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "IAMID")(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && (agg == nil || len(agg.Events) != tt.res.eventLen) {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
return
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
})
}
}
func TestLoginPolicySecondFactorRemovedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Org
new *iam_es_model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove second factor from login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
LoginPolicy: &iam_es_model.LoginPolicy{
AllowUsernamePassword: true,
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
},
}},
new: &iam_es_model.MFA{
MfaType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicySecondFactorRemoved},
},
},
{
name: "existing org nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicySecondFactorRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
})
}
}
func TestLoginPolicyMultiFactorAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Org
new *iam_es_model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "add mfa to login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
},
new: &iam_es_model.MFA{
MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicyMultiFactorAdded},
},
},
{
name: "existing org nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyMultiFactorAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "IAMID")(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && (agg == nil || len(agg.Events) != tt.res.eventLen) {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
return
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
})
}
}
func TestLoginPolicyMultiFactorRemovedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Org
new *iam_es_model.MFA
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "remove mfa from login policy",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
LoginPolicy: &iam_es_model.LoginPolicy{
AllowUsernamePassword: true,
MultiFactors: []int32{
int32(iam_model.MultiFactorTypeU2FWithPIN),
},
}},
new: &iam_es_model.MFA{
MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.LoginPolicyMultiFactorRemoved},
},
},
{
name: "existing org nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "mfa nil",
args: args{
ctx: authz.NewMockContext("orgID", "userID"),
existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}},
new: nil,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := LoginPolicyMultiFactorRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) {
t.Errorf("got wrong err: %v ", err)
return
}
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
})
}

View File

@@ -44,6 +44,57 @@ func (o *Org) appendRemoveIdpProviderFromLoginPolicyEvent(event *es_models.Event
o.LoginPolicy.IDPProviders[i] = o.LoginPolicy.IDPProviders[len(o.LoginPolicy.IDPProviders)-1]
o.LoginPolicy.IDPProviders[len(o.LoginPolicy.IDPProviders)-1] = nil
o.LoginPolicy.IDPProviders = o.LoginPolicy.IDPProviders[:len(o.LoginPolicy.IDPProviders)-1]
return nil
}
return nil
}
func (o *Org) appendAddSecondFactorToLoginPolicyEvent(event *es_models.Event) error {
mfa := &iam_es_model.MFA{}
err := mfa.SetData(event)
if err != nil {
return err
}
o.LoginPolicy.SecondFactors = append(o.LoginPolicy.SecondFactors, mfa.MfaType)
return nil
}
func (o *Org) appendRemoveSecondFactorFromLoginPolicyEvent(event *es_models.Event) error {
mfa := &iam_es_model.MFA{}
err := mfa.SetData(event)
if err != nil {
return err
}
if i, m := iam_es_model.GetMFA(o.LoginPolicy.SecondFactors, mfa.MfaType); m != 0 {
o.LoginPolicy.SecondFactors[i] = o.LoginPolicy.SecondFactors[len(o.LoginPolicy.SecondFactors)-1]
o.LoginPolicy.SecondFactors[len(o.LoginPolicy.SecondFactors)-1] = 0
o.LoginPolicy.SecondFactors = o.LoginPolicy.SecondFactors[:len(o.LoginPolicy.SecondFactors)-1]
return nil
}
return nil
}
func (o *Org) appendAddMultiFactorToLoginPolicyEvent(event *es_models.Event) error {
mfa := &iam_es_model.MFA{}
err := mfa.SetData(event)
if err != nil {
return err
}
o.LoginPolicy.MultiFactors = append(o.LoginPolicy.MultiFactors, mfa.MfaType)
return nil
}
func (o *Org) appendRemoveMultiFactorFromLoginPolicyEvent(event *es_models.Event) error {
mfa := &iam_es_model.MFA{}
err := mfa.SetData(event)
if err != nil {
return err
}
if i, m := iam_es_model.GetMFA(o.LoginPolicy.MultiFactors, mfa.MfaType); m != 0 {
o.LoginPolicy.MultiFactors[i] = o.LoginPolicy.MultiFactors[len(o.LoginPolicy.MultiFactors)-1]
o.LoginPolicy.MultiFactors[len(o.LoginPolicy.MultiFactors)-1] = 0
o.LoginPolicy.MultiFactors = o.LoginPolicy.MultiFactors[:len(o.LoginPolicy.MultiFactors)-1]
return nil
}
return nil
}

View File

@@ -208,3 +208,183 @@ func TestRemoveAddIdpToPolicyEvent(t *testing.T) {
})
}
}
func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
type args struct {
org *Org
mfa *iam_es_model.MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "append add second factor to login policy event",
args: args{
org: &Org{LoginPolicy: &iam_es_model.LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
mfa: &iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.org.appendAddSecondFactorToLoginPolicyEvent(tt.args.event)
if len(tt.result.LoginPolicy.SecondFactors) != len(tt.args.org.LoginPolicy.SecondFactors) {
t.Errorf("got wrong second factor len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.SecondFactors), len(tt.args.org.LoginPolicy.SecondFactors))
}
if tt.result.LoginPolicy.SecondFactors[0] != tt.args.mfa.MfaType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.LoginPolicy.SecondFactors[0], tt.args.mfa)
}
})
}
}
func TestRemoveSecondFactorFromPolicyEvent(t *testing.T) {
type args struct {
org *Org
mfa *iam_es_model.MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "append remove second factor from login policy event",
args: args{
org: &Org{
LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
}}},
mfa: &iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
SecondFactors: []int32{}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.org.appendRemoveSecondFactorFromLoginPolicyEvent(tt.args.event)
if len(tt.result.LoginPolicy.SecondFactors) != len(tt.args.org.LoginPolicy.SecondFactors) {
t.Errorf("got wrong idp mfa len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.SecondFactors), len(tt.args.org.LoginPolicy.SecondFactors))
}
})
}
}
func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
type args struct {
org *Org
mfa *iam_es_model.MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "append add mfa to login policy event",
args: args{
org: &Org{LoginPolicy: &iam_es_model.LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
mfa: &iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
MultiFactors: []int32{
int32(iam_model.MultiFactorTypeU2FWithPIN),
}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.org.appendAddMultiFactorToLoginPolicyEvent(tt.args.event)
if len(tt.result.LoginPolicy.MultiFactors) != len(tt.args.org.LoginPolicy.MultiFactors) {
t.Errorf("got wrong second factor len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.MultiFactors), len(tt.args.org.LoginPolicy.MultiFactors))
}
if tt.result.LoginPolicy.MultiFactors[0] != tt.args.mfa.MfaType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.LoginPolicy.MultiFactors[0], tt.args.mfa)
}
})
}
}
func TestRemoveMultiFactorFromPolicyEvent(t *testing.T) {
type args struct {
org *Org
mfa *iam_es_model.MFA
event *es_models.Event
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "append remove mfa from login policy event",
args: args{
org: &Org{
LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
MultiFactors: []int32{
int32(iam_model.MultiFactorTypeU2FWithPIN),
}}},
mfa: &iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
AllowExternalIdp: true,
AllowRegister: true,
AllowUsernamePassword: true,
MultiFactors: []int32{}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.mfa != nil {
data, _ := json.Marshal(tt.args.mfa)
tt.args.event.Data = data
}
tt.args.org.appendRemoveMultiFactorFromLoginPolicyEvent(tt.args.event)
if len(tt.result.LoginPolicy.MultiFactors) != len(tt.args.org.LoginPolicy.MultiFactors) {
t.Errorf("got wrong idp mfa len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.MultiFactors), len(tt.args.org.LoginPolicy.MultiFactors))
}
})
}
}

View File

@@ -199,6 +199,14 @@ func (o *Org) AppendEvent(event *es_models.Event) (err error) {
err = o.appendAddIdpProviderToLoginPolicyEvent(event)
case LoginPolicyIDPProviderRemoved:
err = o.appendRemoveIdpProviderFromLoginPolicyEvent(event)
case LoginPolicySecondFactorAdded:
err = o.appendAddSecondFactorToLoginPolicyEvent(event)
case LoginPolicySecondFactorRemoved:
err = o.appendRemoveSecondFactorFromLoginPolicyEvent(event)
case LoginPolicyMultiFactorAdded:
err = o.appendAddMultiFactorToLoginPolicyEvent(event)
case LoginPolicyMultiFactorRemoved:
err = o.appendRemoveMultiFactorFromLoginPolicyEvent(event)
case PasswordComplexityPolicyAdded:
err = o.appendAddPasswordComplexityPolicyEvent(event)
case PasswordComplexityPolicyChanged:

View File

@@ -51,9 +51,14 @@ const (
LoginPolicyIDPProviderAdded models.EventType = "org.policy.login.idpprovider.added"
LoginPolicyIDPProviderRemoved models.EventType = "org.policy.login.idpprovider.removed"
LoginPolicyIDPProviderCascadeRemoved models.EventType = "org.policy.login.idpprovider.cascade.removed"
LabelPolicyAdded models.EventType = "org.policy.label.added"
LabelPolicyChanged models.EventType = "org.policy.label.changed"
LabelPolicyRemoved models.EventType = "org.policy.label.removed"
LoginPolicySecondFactorAdded models.EventType = "org.policy.login.secondfactor.added"
LoginPolicySecondFactorRemoved models.EventType = "org.policy.login.secondfactor.removed"
LoginPolicyMultiFactorAdded models.EventType = "org.policy.login.multifactor.added"
LoginPolicyMultiFactorRemoved models.EventType = "org.policy.login.multifactor.removed"
LabelPolicyAdded models.EventType = "org.policy.label.added"
LabelPolicyChanged models.EventType = "org.policy.label.changed"
LabelPolicyRemoved models.EventType = "org.policy.label.removed"
PasswordComplexityPolicyAdded models.EventType = "org.policy.password.complexity.added"
PasswordComplexityPolicyChanged models.EventType = "org.policy.password.complexity.changed"

View File

@@ -86,20 +86,28 @@ Errors:
IDP:
InvalidSearchQuery: Ungültiger Suchparameter
LoginPolicy:
NotFound: Login Policy konnte nicht gefunden werden
Invalid: Login Policy ist ungültig
NotExisting: Login Policy existiert nicht auf dieser Organisation
AlreadyExists: Login Policy existiert bereits
IdpProviderAlreadyExisting: Idp Provider existiert bereits
IdpProviderNotExisting: Idp Provider existiert nicht
MFA:
AlreadyExists: Multifaktor existiert bereits
NotExisting: Multifaktor existiert nicht
Unspecified: Multifaktor ungültig
PasswordComplexity:
NotFound: Password Komplexitäts Policy konnte nicht gefunden werden
Empty: Passwort Komplexitäts Policy ist leer
NotExisting: Passwort Komplexitäts Policy existiert nicht
AlreadyExists: Passwort Komplexitäts Policy existiert bereits
PasswordLockout:
NotFound: Password Lockout Policy konnte nicht gefunden werden
Empty: Passwort Lockout Policy ist leer
NotExisting: Passwort Lockout Policy existiert nicht
AlreadyExists: Passwort Lockout Policy existiert bereits
PasswordAge:
NotFound: Password Age Policy konnte nicht gefunden werden
Empty: Passwort Age Policy ist leer
NotExisting: Passwort Age Policy existiert nicht
AlreadyExists: Passwort Age Policy existiert bereits
@@ -140,7 +148,7 @@ Errors:
GrantNotExists: Projekt Grant existiert nicht
GrantHasNotExistingRole: Eine der Rollen existiert nicht auf dem Projekt
UserIDMisisng: User ID fehlt
Iam:
IAM:
MemberInvalid: Member ist ungültig
MemberAlreadyExisting: Member existiert bereits
MemberNotExisting: Member existiert nicht
@@ -155,23 +163,34 @@ Errors:
LoginPolicyNotExisting: Login Policy nicht vorhanden
IdpProviderInvalid: Idp Provider ist ungültig
LoginPolicy:
NotFound: Default Login Policy konnte nicht gefunden
NotExisting: Default Login Policy existiert nicht
AlreadyExists: Default Login Policy existiert bereits
IdpProviderAlreadyExisting: Idp Provider existiert bereits
IdpProviderNotExisting: Idp Provider existiert nicht
MFA:
AlreadyExists: Multifaktor existiert bereits
NotExisting: Multifaktor existiert nicht
Unspecified: Multifaktor ungültig
LabelPolicy:
NotFound: Default Private Label Policy konnte nicht gefunden
PasswordComplexityPolicy:
NotFound: Default Password Complexity Policy konnte nicht gefunden werden
NotExisting: Default Password Complexity Policy existiert nicht
AlreadyExists: Default Password Complexity Policy existiert bereits
Empty: Default Password Complexity Policy leer
PasswordAgePolicy:
NotFound: Default Password Age Policy konnte nicht gefunden werden
NotExisting: Default Password Age Policy existiert nicht
AlreadyExists: Default Password Age Policy existiert bereits
Empty: Default Password Age Policy leer
PasswordLockoutPolicy:
NotFound: Default Password Lockout Policy konnte nicht gefunden werden
NotExisting: Default Password Lockout Policy existiert nicht
AlreadyExists: Default Password Lockout Policy existiert bereits
Empty: Default Password Lockout Policy leer
OrgIAM:
OrgIAMPolicy:
NotFound: Default Org IAM Policy konnte nicht gefunden werden
NotExisting: Default Org IAM Policy existiert nicht
AlreadyExists: Default Org IAM Policy existiert bereits
Empty: Default Org IAM Policy leer
@@ -192,6 +211,10 @@ Errors:
NotFound: Benutzer Sitzung konnte nicht gefunden werden
Key:
ExpireBeforeNow: Das Ablaufdatum liegt in der Vergangenheit
Login:
LoginPolicy:
MFA:
ForceAndNotConfigured: Multifaktor ist als zwingend konfiguriert, jedoch sind keine möglichen Provider hinterlegt. Bitte melde dich beim Administrator des Systems.
EventTypes:
user:
added: Benutzer hinzugefügt

View File

@@ -91,6 +91,10 @@ Errors:
AlreadyExists: Login Policy already exists
IdpProviderAlreadyExisting: Idp Provider already existing
IdpProviderNotExisting: Idp Provider not existing
MFA:
AlreadyExists: Multifactor already exists
NotExisting: Multifactor not existing
Unspecified: Multifactor invalid
PasswordComplexity:
Empty: Passwort Complexity Policy is empty
NotExisting: Passwort Complexity Policy doesn't exist
@@ -132,7 +136,7 @@ Errors:
GrantNotExists: Project grant doesn't exist
GrantHasNotExistingRole: One role doesn't exist on project
UserIDMisisng: User ID missing
Iam:
IAM:
MemberInvalid: Member is invalid
MemberAlreadyExisting: Member already exists
MemberNotExisting: Member does not exist
@@ -147,31 +151,34 @@ Errors:
LoginPolicyNotExisting: Login Policy doesn't exist
IdpProviderInvalid: Idp Provider is invalid
LoginPolicy:
NotFound: Default Login Policy not found
NotExisting: Default Login Policy not existig
AlreadyExists: Default Login Policy already exists
IdpProviderAlreadyExisting: Idp Provider already existing
IdpProviderNotExisting: Idp Provider not existing
MFA:
AlreadyExists: Multifactor already exists
NotExisting: Multifactor not existing
Unspecified: Multifactor invalid
LabelPolicy:
NotFound: Default Private Label Policy not found
PasswordComplexityPolicy:
NotFound: Default Private Label Policy not found
NotExisting: Default Password Complexity Policy not existing
AlreadyExists: Default Password Complexity Policy already existing
Empty: Default Password Complexity Policy empty
PasswordAgePolicy:
NotFound: Default Password Age Policy not found
NotExisting: Default Password Age Policy not existing
AlreadyExists: Default Password Age Policy already existing
Empty: Default Password Age Policy empty
PasswordLockoutPolicy:
NotFound: Default Password Lockout Policy not found
NotExisting: Default Password Lockout Policy not existing
AlreadyExists: Default Password Lockout Policy already existing
Empty: Default Password Lockout Policy empty
PasswordLockout:
Empty: Passwort Lockout Policy is empty
NotExisting: Passwort Lockout Policy not existing
AlreadyExists: Passwort Lockout Policy already exists
PasswordAge:
Empty: Passwort Age Policy is empty
NotExisting: Passwort Age Policy not existing
AlreadyExists: Passwort Age Policy already exists
OrgIAM:
OrgIAMPolicy:
NotFound: Org IAM Policy not found
Empty: Org IAM Policy is empty
NotExisting: Org IAM Policy not existing
AlreadyExists: Org IAM Policy already exists
@@ -192,6 +199,10 @@ Errors:
NotFound: UserSession not found
Key:
ExpireBeforeNow: The expiration date is in the past
Login:
LoginPolicy:
MFA:
ForceAndNotConfigured: Multifactor is configured as required, but no possible providers are configured. Please contact your system administrator.
EventTypes:
user:
added: User added

View File

@@ -16,7 +16,7 @@ const (
)
type mfaInitVerifyData struct {
MfaType model.MfaType `schema:"mfaType"`
MfaType model.MFAType `schema:"mfaType"`
Code string `schema:"code"`
URL string `schema:"url"`
Secret string `schema:"secret"`
@@ -31,7 +31,7 @@ func (l *Login) handleMfaInitVerify(w http.ResponseWriter, r *http.Request) {
}
var verifyData *mfaVerifyData
switch data.MfaType {
case model.MfaTypeOTP:
case model.MFATypeOTP:
verifyData = l.handleOtpVerify(w, r, authReq, data)
}
@@ -69,7 +69,7 @@ func (l *Login) renderMfaInitVerify(w http.ResponseWriter, r *http.Request, auth
}
data.baseData = l.getBaseData(r, authReq, "Mfa Init Verify", errType, errMessage)
data.profileData = l.getProfileData(authReq)
if data.MfaType == model.MfaTypeOTP {
if data.MfaType == model.MFATypeOTP {
code, err := generateQrCode(data.otpData.Url)
if err == nil {
data.otpData.QrCode = code

View File

@@ -12,7 +12,7 @@ const (
)
type mfaPromptData struct {
MfaProvider model.MfaType `schema:"provider"`
MfaProvider model.MFAType `schema:"provider"`
Skip bool `schema:"skip"`
}
@@ -78,7 +78,7 @@ func (l *Login) renderMfaPrompt(w http.ResponseWriter, r *http.Request, authReq
func (l *Login) handleMfaCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) {
switch data.MfaType {
case model.MfaTypeOTP:
case model.MFATypeOTP:
l.handleOtpCreation(w, r, authReq, data)
return
}

View File

@@ -12,7 +12,7 @@ const (
)
type mfaVerifyFormData struct {
MfaType model.MfaType `schema:"mfaType"`
MfaType model.MFAType `schema:"mfaType"`
Code string `schema:"code"`
}
@@ -23,7 +23,7 @@ func (l *Login) handleMfaVerify(w http.ResponseWriter, r *http.Request) {
l.renderError(w, r, authReq, err)
return
}
if data.MfaType == model.MfaTypeOTP {
if data.MfaType == model.MFATypeOTP {
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.VerifyMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, userAgentID, model.BrowserInfoFromRequest(r))
}

View File

@@ -98,7 +98,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
"mfaPromptUrl": func() string {
return path.Join(r.pathPrefix, EndpointMfaPrompt)
},
"mfaPromptChangeUrl": func(id string, provider model.MfaType) string {
"mfaPromptChangeUrl": func(id string, provider model.MFAType) string {
return path.Join(r.pathPrefix, fmt.Sprintf("%s?%s=%s;%s=%v", EndpointMfaPrompt, queryAuthRequestID, id, "provider", provider))
},
"mfaInitVerifyUrl": func() string {
@@ -158,7 +158,7 @@ func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq *
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
authReq, err := l.authRepo.AuthRequestByID(r.Context(), authReq.ID, userAgentID)
if err != nil {
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-sio0W", "could not get authreq"))
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(err, "APP-sio0W", "could not get authreq"))
return
}
if len(authReq.PossibleSteps) == 0 {
@@ -356,8 +356,8 @@ type userData struct {
baseData
profileData
PasswordChecked string
MfaProviders []model.MfaType
SelectedMfaProvider model.MfaType
MfaProviders []model.MFAType
SelectedMfaProvider model.MFAType
Linking bool
}
@@ -386,21 +386,21 @@ type userSelectionData struct {
type mfaData struct {
baseData
profileData
MfaProviders []model.MfaType
MfaProviders []model.MFAType
MfaRequired bool
}
type mfaVerifyData struct {
baseData
profileData
MfaType model.MfaType
MfaType model.MFAType
otpData
}
type mfaDoneData struct {
baseData
profileData
MfaType model.MfaType
MfaType model.MFAType
}
type otpData struct {

View File

@@ -66,8 +66,8 @@ InitUserDone:
MfaPrompt:
Title: Multifaktor hinzufügen
Description: Möchtest du einen Mulitfaktor hinzufügen?
Provider0: OTP
Provider1: SMS
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
MfaInitVerify:
Title: Multifaktor Verifizierung

View File

@@ -66,8 +66,8 @@ InitUserDone:
MfaPrompt:
Title: Multifactor Setup
Description: Would you like to setup multifactor authentication?
Provider0: OTP
Provider1: SMS
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
MfaInitVerify:
Title: Multifactor Verification

View File

@@ -8,23 +8,23 @@ import (
)
type UserSessionView struct {
CreationDate time.Time
ChangeDate time.Time
State req_model.UserSessionState
ResourceOwner string
UserAgentID string
UserID string
UserName string
LoginName string
DisplayName string
SelectedIDPConfigID string
PasswordVerification time.Time
ExternalLoginVerification time.Time
MfaSoftwareVerification time.Time
MfaSoftwareVerificationType req_model.MfaType
MfaHardwareVerification time.Time
MfaHardwareVerificationType req_model.MfaType
Sequence uint64
CreationDate time.Time
ChangeDate time.Time
State req_model.UserSessionState
ResourceOwner string
UserAgentID string
UserID string
UserName string
LoginName string
DisplayName string
SelectedIDPConfigID string
PasswordVerification time.Time
ExternalLoginVerification time.Time
SecondFactorVerification time.Time
SecondFactorVerificationType req_model.MFAType
MultiFactorVerification time.Time
MultiFactorVerificationType req_model.MFAType
Sequence uint64
}
type UserSessionSearchRequest struct {

View File

@@ -1,6 +1,7 @@
package model
import (
iam_model "github.com/caos/zitadel/internal/iam/model"
"time"
req_model "github.com/caos/zitadel/internal/auth_request/model"
@@ -46,7 +47,7 @@ type HumanView struct {
Region string
StreetAddress string
OTPState MfaState
MfaMaxSetUp req_model.MfaLevel
MfaMaxSetUp req_model.MFALevel
MfaInitSkipped time.Time
InitRequired bool
}
@@ -107,40 +108,87 @@ func (r *UserSearchRequest) AppendMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &UserSearchQuery{Key: UserSearchKeyResourceOwner, Method: model.SearchMethodEquals, Value: orgID})
}
func (u *UserView) MfaTypesSetupPossible(level req_model.MfaLevel) []req_model.MfaType {
types := make([]req_model.MfaType, 0)
func (u *UserView) MfaTypesSetupPossible(level req_model.MFALevel, policy *iam_model.LoginPolicyView) []req_model.MFAType {
types := make([]req_model.MFAType, 0)
switch level {
default:
fallthrough
case req_model.MfaLevelSoftware:
if u.OTPState != MfaStateReady {
types = append(types, req_model.MfaTypeOTP)
case req_model.MFALevelSecondFactor:
if policy.HasSecondFactors() {
for _, mfaType := range policy.SecondFactors {
switch mfaType {
case iam_model.SecondFactorTypeOTP:
if u.OTPState != MfaStateReady {
types = append(types, req_model.MFATypeOTP)
}
}
}
}
//PLANNED: add sms
fallthrough
case req_model.MfaLevelHardware:
case req_model.MFALevelMultiFactor:
if policy.HasMultiFactors() {
for _, mfaType := range policy.MultiFactors {
switch mfaType {
case iam_model.MultiFactorTypeU2FWithPIN:
// TODO: Check if not set up already
// types = append(types, req_model.MFATypeU2F)
}
}
}
//PLANNED: add token
}
return types
}
func (u *UserView) MfaTypesAllowed(level req_model.MfaLevel) []req_model.MfaType {
types := make([]req_model.MfaType, 0)
func (u *UserView) MfaTypesAllowed(level req_model.MFALevel, policy *iam_model.LoginPolicyView) []req_model.MFAType {
types := make([]req_model.MFAType, 0)
switch level {
default:
fallthrough
case req_model.MfaLevelSoftware:
if u.OTPState == MfaStateReady {
types = append(types, req_model.MfaTypeOTP)
case req_model.MFALevelSecondFactor:
if policy.HasSecondFactors() {
for _, mfaType := range policy.SecondFactors {
switch mfaType {
case iam_model.SecondFactorTypeOTP:
if u.OTPState == MfaStateReady {
types = append(types, req_model.MFATypeOTP)
}
}
}
}
//PLANNED: add sms
fallthrough
case req_model.MfaLevelHardware:
case req_model.MFALevelMultiFactor:
if policy.HasMultiFactors() {
for _, mfaType := range policy.MultiFactors {
switch mfaType {
case iam_model.MultiFactorTypeU2FWithPIN:
// TODO: Check if not set up already
// types = append(types, req_model.MFATypeU2F)
}
}
}
//PLANNED: add token
}
return types
}
func (u *UserView) HasRequiredOrgMFALevel(policy *iam_model.LoginPolicyView) bool {
if !policy.ForceMFA {
return true
}
switch u.MfaMaxSetUp {
case req_model.MFALevelSecondFactor:
return policy.HasSecondFactors()
case req_model.MFALevelMultiFactor:
return true
default:
return false
}
}
func (u *UserView) GetProfile() (*Profile, error) {
if u.HumanView == nil {
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-WLTce", "Errors.User.NotHuman")

View File

@@ -140,7 +140,7 @@ func UserToModel(user *UserView) *model.UserView {
Region: user.Region,
StreetAddress: user.StreetAddress,
OTPState: model.MfaState(user.OTPState),
MfaMaxSetUp: req_model.MfaLevel(user.MfaMaxSetUp),
MfaMaxSetUp: req_model.MFALevel(user.MfaMaxSetUp),
MfaInitSkipped: user.MfaInitSkipped,
InitRequired: user.InitRequired,
}
@@ -313,9 +313,9 @@ func (u *UserView) ComputeObject() {
}
}
if u.OTPState != int32(model.MfaStateReady) {
u.MfaMaxSetUp = int32(req_model.MfaLevelNotSetUp)
u.MfaMaxSetUp = int32(req_model.MFALevelNotSetUp)
}
if u.OTPState == int32(model.MfaStateReady) {
u.MfaMaxSetUp = int32(req_model.MfaLevelSoftware)
u.MfaMaxSetUp = int32(req_model.MFALevelSecondFactor)
}
}

View File

@@ -21,23 +21,23 @@ const (
)
type UserSessionView struct {
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
State int32 `json:"-" gorm:"column:state"`
UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id;primary_key"`
UserID string `json:"userID" gorm:"column:user_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
LoginName string `json:"-" gorm:"column:login_name"`
DisplayName string `json:"-" gorm:"column:user_display_name"`
SelectedIDPConfigID string `json:"selectedIDPConfigID" gorm:"column:selected_idp_config_id"`
PasswordVerification time.Time `json:"-" gorm:"column:password_verification"`
ExternalLoginVerification time.Time `json:"-" gorm:"column:external_login_verification"`
MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"`
MfaSoftwareVerificationType int32 `json:"-" gorm:"column:mfa_software_verification_type"`
MfaHardwareVerification time.Time `json:"-" gorm:"column:mfa_hardware_verification"`
MfaHardwareVerificationType int32 `json:"-" gorm:"column:mfa_hardware_verification_type"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
State int32 `json:"-" gorm:"column:state"`
UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id;primary_key"`
UserID string `json:"userID" gorm:"column:user_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
LoginName string `json:"-" gorm:"column:login_name"`
DisplayName string `json:"-" gorm:"column:user_display_name"`
SelectedIDPConfigID string `json:"selectedIDPConfigID" gorm:"column:selected_idp_config_id"`
PasswordVerification time.Time `json:"-" gorm:"column:password_verification"`
ExternalLoginVerification time.Time `json:"-" gorm:"column:external_login_verification"`
SecondFactorVerification time.Time `json:"-" gorm:"column:second_factor_verification"`
SecondFactorVerificationType int32 `json:"-" gorm:"column:second_factor_verification_type"`
MultiFactorVerification time.Time `json:"-" gorm:"column:multi_factor_verification"`
MultiFactorVerificationType int32 `json:"-" gorm:"column:multi_factor_verification_type"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) {
@@ -51,23 +51,23 @@ func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) {
func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView {
return &model.UserSessionView{
ChangeDate: userSession.ChangeDate,
CreationDate: userSession.CreationDate,
ResourceOwner: userSession.ResourceOwner,
State: req_model.UserSessionState(userSession.State),
UserAgentID: userSession.UserAgentID,
UserID: userSession.UserID,
UserName: userSession.UserName,
LoginName: userSession.LoginName,
DisplayName: userSession.DisplayName,
SelectedIDPConfigID: userSession.SelectedIDPConfigID,
PasswordVerification: userSession.PasswordVerification,
ExternalLoginVerification: userSession.ExternalLoginVerification,
MfaSoftwareVerification: userSession.MfaSoftwareVerification,
MfaSoftwareVerificationType: req_model.MfaType(userSession.MfaSoftwareVerificationType),
MfaHardwareVerification: userSession.MfaHardwareVerification,
MfaHardwareVerificationType: req_model.MfaType(userSession.MfaHardwareVerificationType),
Sequence: userSession.Sequence,
ChangeDate: userSession.ChangeDate,
CreationDate: userSession.CreationDate,
ResourceOwner: userSession.ResourceOwner,
State: req_model.UserSessionState(userSession.State),
UserAgentID: userSession.UserAgentID,
UserID: userSession.UserID,
UserName: userSession.UserName,
LoginName: userSession.LoginName,
DisplayName: userSession.DisplayName,
SelectedIDPConfigID: userSession.SelectedIDPConfigID,
PasswordVerification: userSession.PasswordVerification,
ExternalLoginVerification: userSession.ExternalLoginVerification,
SecondFactorVerification: userSession.SecondFactorVerification,
SecondFactorVerificationType: req_model.MFAType(userSession.SecondFactorVerificationType),
MultiFactorVerification: userSession.MultiFactorVerification,
MultiFactorVerificationType: req_model.MFAType(userSession.MultiFactorVerificationType),
Sequence: userSession.Sequence,
}
}
@@ -100,20 +100,20 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
v.PasswordVerification = time.Time{}
case es_model.MFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded:
v.MfaSoftwareVerification = event.CreationDate
v.MfaSoftwareVerificationType = int32(req_model.MfaTypeOTP)
v.SecondFactorVerification = event.CreationDate
v.SecondFactorVerificationType = int32(req_model.MFATypeOTP)
v.State = int32(req_model.UserSessionStateActive)
case es_model.MFAOTPCheckFailed,
es_model.MFAOTPRemoved,
es_model.HumanMFAOTPCheckFailed,
es_model.HumanMFAOTPRemoved:
v.MfaSoftwareVerification = time.Time{}
v.SecondFactorVerification = time.Time{}
case es_model.SignedOut,
es_model.HumanSignedOut,
es_model.UserLocked,
es_model.UserDeactivated:
v.PasswordVerification = time.Time{}
v.MfaSoftwareVerification = time.Time{}
v.SecondFactorVerification = time.Time{}
v.ExternalLoginVerification = time.Time{}
v.State = int32(req_model.UserSessionStateTerminated)
}

View File

@@ -78,7 +78,7 @@ func TestAppendEvent(t *testing.T) {
event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPCheckSucceeded},
userView: &UserSessionView{},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: now()},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: now()},
},
{
name: "append human otp check succeeded event",
@@ -86,55 +86,55 @@ func TestAppendEvent(t *testing.T) {
event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPCheckSucceeded},
userView: &UserSessionView{},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: now()},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: now()},
},
{
name: "append user otp check failed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPCheckFailed},
userView: &UserSessionView{MfaSoftwareVerification: now()},
userView: &UserSessionView{SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
},
{
name: "append human otp check failed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPCheckFailed},
userView: &UserSessionView{MfaSoftwareVerification: now()},
userView: &UserSessionView{SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
},
{
name: "append user otp removed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPRemoved},
userView: &UserSessionView{MfaSoftwareVerification: now()},
userView: &UserSessionView{SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
},
{
name: "append human otp removed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPRemoved},
userView: &UserSessionView{MfaSoftwareVerification: now()},
userView: &UserSessionView{SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}},
result: &UserSessionView{ChangeDate: now(), SecondFactorVerification: time.Time{}},
},
{
name: "append user signed out event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.SignedOut},
userView: &UserSessionView{PasswordVerification: now(), MfaSoftwareVerification: now()},
userView: &UserSessionView{PasswordVerification: now(), SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, MfaSoftwareVerification: time.Time{}, State: 1},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, SecondFactorVerification: time.Time{}, State: 1},
},
{
name: "append human signed out event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.HumanSignedOut},
userView: &UserSessionView{PasswordVerification: now(), MfaSoftwareVerification: now()},
userView: &UserSessionView{PasswordVerification: now(), SecondFactorVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, MfaSoftwareVerification: time.Time{}, State: 1},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, SecondFactorVerification: time.Time{}, State: 1},
},
}
for _, tt := range tests {

View File

@@ -0,0 +1,21 @@
ALTER TABLE management.login_policies ADD COLUMN force_mfa BOOLEAN;
ALTER TABLE adminapi.login_policies ADD COLUMN force_mfa BOOLEAN;
ALTER TABLE auth.login_policies ADD COLUMN force_mfa BOOLEAN;
ALTER TABLE management.login_policies ADD COLUMN second_factors SMALLINT ARRAY;
ALTER TABLE adminapi.login_policies ADD COLUMN second_factors SMALLINT ARRAY;
ALTER TABLE auth.login_policies ADD COLUMN second_factors SMALLINT ARRAY;
ALTER TABLE management.login_policies ADD COLUMN multi_factors SMALLINT ARRAY;
ALTER TABLE adminapi.login_policies ADD COLUMN multi_factors SMALLINT ARRAY;
ALTER TABLE auth.login_policies ADD COLUMN multi_factors SMALLINT ARRAY;
ALTER TABLE auth.user_sessions RENAME COLUMN mfa_software_verification TO second_factor_verification;
ALTER TABLE auth.user_sessions RENAME COLUMN mfa_software_verification_type TO second_factor_verification_type;
ALTER TABLE auth.user_sessions RENAME COLUMN mfa_hardware_verification TO multi_factor_verification;
ALTER TABLE auth.user_sessions RENAME COLUMN mfa_hardware_verification_type TO multi_factor_verification_type;

View File

@@ -184,6 +184,36 @@ var AdminService_AuthMethods = authz.MethodMapping{
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/GetDefaultLoginPolicySecondFactors": authz.Option{
Permission: "iam.policy.read",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/AddSecondFactorToDefaultLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/RemoveSecondFactorFromDefaultLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/GetDefaultLoginPolicyMultiFactors": authz.Option{
Permission: "iam.policy.read",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/AddMultiFactorToDefaultLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/RemoveMultiFactorFromDefaultLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.admin.api.v1.AdminService/GetDefaultPasswordComplexityPolicy": authz.Option{
Permission: "iam.policy.read",
CheckParam: "",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4496,6 +4496,8 @@ func (m *DefaultLoginPolicy) Validate() error {
}
}
// no validation rules for ForceMfa
return nil
}
@@ -4569,6 +4571,8 @@ func (m *DefaultLoginPolicyRequest) Validate() error {
// no validation rules for AllowExternalIdp
// no validation rules for ForceMfa
return nil
}
@@ -4734,6 +4738,8 @@ func (m *DefaultLoginPolicyView) Validate() error {
}
}
// no validation rules for ForceMfa
return nil
}
@@ -5035,6 +5041,274 @@ var _ interface {
ErrorName() string
} = IdpProviderSearchRequestValidationError{}
// Validate checks the field values on SecondFactorsResult with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
func (m *SecondFactorsResult) Validate() error {
if m == nil {
return nil
}
return nil
}
// SecondFactorsResultValidationError is the validation error returned by
// SecondFactorsResult.Validate if the designated constraints aren't met.
type SecondFactorsResultValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e SecondFactorsResultValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e SecondFactorsResultValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e SecondFactorsResultValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e SecondFactorsResultValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e SecondFactorsResultValidationError) ErrorName() string {
return "SecondFactorsResultValidationError"
}
// Error satisfies the builtin error interface
func (e SecondFactorsResultValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sSecondFactorsResult.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = SecondFactorsResultValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = SecondFactorsResultValidationError{}
// Validate checks the field values on SecondFactor with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *SecondFactor) Validate() error {
if m == nil {
return nil
}
// no validation rules for SecondFactor
return nil
}
// SecondFactorValidationError is the validation error returned by
// SecondFactor.Validate if the designated constraints aren't met.
type SecondFactorValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e SecondFactorValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e SecondFactorValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e SecondFactorValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e SecondFactorValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e SecondFactorValidationError) ErrorName() string { return "SecondFactorValidationError" }
// Error satisfies the builtin error interface
func (e SecondFactorValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sSecondFactor.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = SecondFactorValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = SecondFactorValidationError{}
// Validate checks the field values on MultiFactorsResult with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
func (m *MultiFactorsResult) Validate() error {
if m == nil {
return nil
}
return nil
}
// MultiFactorsResultValidationError is the validation error returned by
// MultiFactorsResult.Validate if the designated constraints aren't met.
type MultiFactorsResultValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e MultiFactorsResultValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorsResultValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorsResultValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorsResultValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorsResultValidationError) ErrorName() string {
return "MultiFactorsResultValidationError"
}
// Error satisfies the builtin error interface
func (e MultiFactorsResultValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sMultiFactorsResult.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorsResultValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = MultiFactorsResultValidationError{}
// Validate checks the field values on MultiFactor with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *MultiFactor) Validate() error {
if m == nil {
return nil
}
// no validation rules for MultiFactor
return nil
}
// MultiFactorValidationError is the validation error returned by
// MultiFactor.Validate if the designated constraints aren't met.
type MultiFactorValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e MultiFactorValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorValidationError) ErrorName() string { return "MultiFactorValidationError" }
// Error satisfies the builtin error interface
func (e MultiFactorValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sMultiFactor.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = MultiFactorValidationError{}
// Validate checks the field values on DefaultPasswordComplexityPolicy with the
// rules defined in the proto definition for this message. If any rules are
// violated, an error is returned.

View File

@@ -30,7 +30,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -52,7 +52,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -96,7 +96,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -118,7 +118,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -150,7 +150,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -182,7 +182,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -220,7 +220,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -248,7 +248,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -276,7 +276,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -314,7 +314,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -352,7 +352,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -390,7 +390,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -422,7 +422,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -454,7 +454,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -476,7 +476,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -504,7 +504,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -543,7 +543,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -579,7 +579,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -611,7 +611,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -644,7 +644,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -664,7 +664,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -696,7 +696,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -726,7 +726,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -754,7 +754,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -782,7 +782,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -818,7 +818,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -856,7 +856,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -876,7 +876,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -908,7 +908,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -928,7 +928,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -960,7 +960,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -992,7 +992,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1024,7 +1024,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1043,6 +1043,183 @@
]
}
},
"/policies/login/multifactors": {
"post": {
"operationId": "AdminService_AddMultiFactorToDefaultLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1MultiFactor"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1MultiFactor"
}
}
],
"tags": [
"AdminService"
]
}
},
"/policies/login/multifactors/_search": {
"get": {
"operationId": "AdminService_GetDefaultLoginPolicyMultiFactors",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1MultiFactorsResult"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"tags": [
"AdminService"
]
}
},
"/policies/login/multifactors/{multi_factor}": {
"delete": {
"operationId": "AdminService_RemoveMultiFactorFromDefaultLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "multi_factor",
"in": "path",
"required": true,
"type": "string",
"enum": [
"MULTIFACTORTYPE_UNSPECIFIED",
"MULTIFACTORTYPE_U2F_WITH_PIN"
]
}
],
"tags": [
"AdminService"
]
}
},
"/policies/login/secondfactors": {
"post": {
"operationId": "AdminService_AddSecondFactorToDefaultLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1SecondFactor"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1SecondFactor"
}
}
],
"tags": [
"AdminService"
]
}
},
"/policies/login/secondfactors/_search": {
"get": {
"operationId": "AdminService_GetDefaultLoginPolicySecondFactors",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1SecondFactorsResult"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"tags": [
"AdminService"
]
}
},
"/policies/login/secondfactors/{second_factor}": {
"delete": {
"operationId": "AdminService_RemoveSecondFactorFromDefaultLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "second_factor",
"in": "path",
"required": true,
"type": "string",
"enum": [
"SECONDFACTORTYPE_UNSPECIFIED",
"SECONDFACTORTYPE_OTP",
"SECONDFACTORTYPE_U2F"
]
}
],
"tags": [
"AdminService"
]
}
},
"/policies/password/age": {
"get": {
"operationId": "AdminService_GetDefaultPasswordAgePolicy",
@@ -1054,7 +1231,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1074,7 +1251,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1106,7 +1283,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1126,7 +1303,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1158,7 +1335,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1178,7 +1355,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1211,7 +1388,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1233,7 +1410,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1255,7 +1432,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1277,7 +1454,7 @@
}
},
"default": {
"description": "An unexpected error response.",
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
@@ -1398,13 +1575,15 @@
"type": "string"
},
"is_email_verified": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"phone": {
"type": "string"
},
"is_phone_verified": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"country": {
"type": "string"
@@ -1515,13 +1694,16 @@
"type": "object",
"properties": {
"allow_username_password": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_register": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_external_idp": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1530,6 +1712,10 @@
"change_date": {
"type": "string",
"format": "date-time"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -1537,13 +1723,20 @@
"type": "object",
"properties": {
"allow_username_password": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_register": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_external_idp": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -1551,13 +1744,16 @@
"type": "object",
"properties": {
"allow_username_password": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_register": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"allow_external_idp": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1566,6 +1762,10 @@
"change_date": {
"type": "string",
"format": "date-time"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -1632,16 +1832,20 @@
"format": "uint64"
},
"has_uppercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_lowercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_number": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_symbol": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1661,16 +1865,20 @@
"format": "uint64"
},
"has_uppercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_lowercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_number": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_symbol": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
}
}
},
@@ -1682,16 +1890,20 @@
"format": "uint64"
},
"has_uppercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_lowercase": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_number": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"has_symbol": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1711,7 +1923,8 @@
"format": "uint64"
},
"show_lockout_failure": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1731,7 +1944,8 @@
"format": "uint64"
},
"show_lockout_failure": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
}
}
},
@@ -1743,7 +1957,8 @@
"format": "uint64"
},
"show_lockout_failure": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"creation_date": {
"type": "string",
@@ -1823,13 +2038,15 @@
"type": "string"
},
"is_email_verified": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"phone": {
"type": "string"
},
"is_phone_verified": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"country": {
"type": "string"
@@ -2300,6 +2517,33 @@
}
}
},
"v1MultiFactor": {
"type": "object",
"properties": {
"multi_factor": {
"$ref": "#/definitions/v1MultiFactorType"
}
}
},
"v1MultiFactorType": {
"type": "string",
"enum": [
"MULTIFACTORTYPE_UNSPECIFIED",
"MULTIFACTORTYPE_U2F_WITH_PIN"
],
"default": "MULTIFACTORTYPE_UNSPECIFIED"
},
"v1MultiFactorsResult": {
"type": "object",
"properties": {
"multi_factors": {
"type": "array",
"items": {
"$ref": "#/definitions/v1MultiFactorType"
}
}
}
},
"v1OIDCMappingField": {
"type": "string",
"enum": [
@@ -2445,10 +2689,12 @@
"type": "string"
},
"user_login_must_be_domain": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"default": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"sequence": {
"type": "string",
@@ -2474,7 +2720,8 @@
"type": "string"
},
"user_login_must_be_domain": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
}
}
},
@@ -2485,10 +2732,12 @@
"type": "string"
},
"user_login_must_be_domain": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"default": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"sequence": {
"type": "string",
@@ -2552,7 +2801,8 @@
"$ref": "#/definitions/v1OrgSearchKey"
},
"asc": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
},
"queries": {
"type": "array",
@@ -2641,11 +2891,40 @@
],
"default": "SEARCHMETHOD_EQUALS"
},
"v1SecondFactor": {
"type": "object",
"properties": {
"second_factor": {
"$ref": "#/definitions/v1SecondFactorType"
}
}
},
"v1SecondFactorType": {
"type": "string",
"enum": [
"SECONDFACTORTYPE_UNSPECIFIED",
"SECONDFACTORTYPE_OTP",
"SECONDFACTORTYPE_U2F"
],
"default": "SECONDFACTORTYPE_UNSPECIFIED"
},
"v1SecondFactorsResult": {
"type": "object",
"properties": {
"second_factors": {
"type": "array",
"items": {
"$ref": "#/definitions/v1SecondFactorType"
}
}
}
},
"v1UniqueOrgResponse": {
"type": "object",
"properties": {
"is_unique": {
"type": "boolean"
"type": "boolean",
"format": "boolean"
}
}
},

View File

@@ -77,6 +77,46 @@ func (mr *MockAdminServiceClientMockRecorder) AddIdpProviderToDefaultLoginPolicy
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddIdpProviderToDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).AddIdpProviderToDefaultLoginPolicy), varargs...)
}
// AddMultiFactorToDefaultLoginPolicy mocks base method
func (m *MockAdminServiceClient) AddMultiFactorToDefaultLoginPolicy(arg0 context.Context, arg1 *admin.MultiFactor, arg2 ...grpc.CallOption) (*admin.MultiFactor, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddMultiFactorToDefaultLoginPolicy", varargs...)
ret0, _ := ret[0].(*admin.MultiFactor)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddMultiFactorToDefaultLoginPolicy indicates an expected call of AddMultiFactorToDefaultLoginPolicy
func (mr *MockAdminServiceClientMockRecorder) AddMultiFactorToDefaultLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMultiFactorToDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).AddMultiFactorToDefaultLoginPolicy), varargs...)
}
// AddSecondFactorToDefaultLoginPolicy mocks base method
func (m *MockAdminServiceClient) AddSecondFactorToDefaultLoginPolicy(arg0 context.Context, arg1 *admin.SecondFactor, arg2 ...grpc.CallOption) (*admin.SecondFactor, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddSecondFactorToDefaultLoginPolicy", varargs...)
ret0, _ := ret[0].(*admin.SecondFactor)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddSecondFactorToDefaultLoginPolicy indicates an expected call of AddSecondFactorToDefaultLoginPolicy
func (mr *MockAdminServiceClientMockRecorder) AddSecondFactorToDefaultLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSecondFactorToDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).AddSecondFactorToDefaultLoginPolicy), varargs...)
}
// ChangeIamMember mocks base method
func (m *MockAdminServiceClient) ChangeIamMember(arg0 context.Context, arg1 *admin.ChangeIamMemberRequest, arg2 ...grpc.CallOption) (*admin.IamMember, error) {
m.ctrl.T.Helper()
@@ -237,6 +277,46 @@ func (mr *MockAdminServiceClientMockRecorder) GetDefaultLoginPolicyIdpProviders(
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultLoginPolicyIdpProviders", reflect.TypeOf((*MockAdminServiceClient)(nil).GetDefaultLoginPolicyIdpProviders), varargs...)
}
// GetDefaultLoginPolicyMultiFactors mocks base method
func (m *MockAdminServiceClient) GetDefaultLoginPolicyMultiFactors(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*admin.MultiFactorsResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetDefaultLoginPolicyMultiFactors", varargs...)
ret0, _ := ret[0].(*admin.MultiFactorsResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetDefaultLoginPolicyMultiFactors indicates an expected call of GetDefaultLoginPolicyMultiFactors
func (mr *MockAdminServiceClientMockRecorder) GetDefaultLoginPolicyMultiFactors(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultLoginPolicyMultiFactors", reflect.TypeOf((*MockAdminServiceClient)(nil).GetDefaultLoginPolicyMultiFactors), varargs...)
}
// GetDefaultLoginPolicySecondFactors mocks base method
func (m *MockAdminServiceClient) GetDefaultLoginPolicySecondFactors(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*admin.SecondFactorsResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetDefaultLoginPolicySecondFactors", varargs...)
ret0, _ := ret[0].(*admin.SecondFactorsResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetDefaultLoginPolicySecondFactors indicates an expected call of GetDefaultLoginPolicySecondFactors
func (mr *MockAdminServiceClientMockRecorder) GetDefaultLoginPolicySecondFactors(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultLoginPolicySecondFactors", reflect.TypeOf((*MockAdminServiceClient)(nil).GetDefaultLoginPolicySecondFactors), varargs...)
}
// GetDefaultOrgIamPolicy mocks base method
func (m *MockAdminServiceClient) GetDefaultOrgIamPolicy(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*admin.OrgIamPolicyView, error) {
m.ctrl.T.Helper()
@@ -597,6 +677,26 @@ func (mr *MockAdminServiceClientMockRecorder) RemoveIdpProviderFromDefaultLoginP
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveIdpProviderFromDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).RemoveIdpProviderFromDefaultLoginPolicy), varargs...)
}
// RemoveMultiFactorFromDefaultLoginPolicy mocks base method
func (m *MockAdminServiceClient) RemoveMultiFactorFromDefaultLoginPolicy(arg0 context.Context, arg1 *admin.MultiFactor, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "RemoveMultiFactorFromDefaultLoginPolicy", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RemoveMultiFactorFromDefaultLoginPolicy indicates an expected call of RemoveMultiFactorFromDefaultLoginPolicy
func (mr *MockAdminServiceClientMockRecorder) RemoveMultiFactorFromDefaultLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMultiFactorFromDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).RemoveMultiFactorFromDefaultLoginPolicy), varargs...)
}
// RemoveOrgIamPolicy mocks base method
func (m *MockAdminServiceClient) RemoveOrgIamPolicy(arg0 context.Context, arg1 *admin.OrgIamPolicyID, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
@@ -617,6 +717,26 @@ func (mr *MockAdminServiceClientMockRecorder) RemoveOrgIamPolicy(arg0, arg1 inte
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveOrgIamPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).RemoveOrgIamPolicy), varargs...)
}
// RemoveSecondFactorFromDefaultLoginPolicy mocks base method
func (m *MockAdminServiceClient) RemoveSecondFactorFromDefaultLoginPolicy(arg0 context.Context, arg1 *admin.SecondFactor, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "RemoveSecondFactorFromDefaultLoginPolicy", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RemoveSecondFactorFromDefaultLoginPolicy indicates an expected call of RemoveSecondFactorFromDefaultLoginPolicy
func (mr *MockAdminServiceClientMockRecorder) RemoveSecondFactorFromDefaultLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSecondFactorFromDefaultLoginPolicy", reflect.TypeOf((*MockAdminServiceClient)(nil).RemoveSecondFactorFromDefaultLoginPolicy), varargs...)
}
// SearchIamMembers mocks base method
func (m *MockAdminServiceClient) SearchIamMembers(arg0 context.Context, arg1 *admin.IamMemberSearchRequest, arg2 ...grpc.CallOption) (*admin.IamMemberSearchResponse, error) {
m.ctrl.T.Helper()

View File

@@ -416,6 +416,68 @@ service AdminService {
};
}
rpc GetDefaultLoginPolicySecondFactors(google.protobuf.Empty) returns (SecondFactorsResult) {
option (google.api.http) = {
get: "/policies/login/secondfactors/_search"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.read"
};
}
rpc AddSecondFactorToDefaultLoginPolicy(SecondFactor) returns (SecondFactor) {
option (google.api.http) = {
post: "/policies/login/secondfactors"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc RemoveSecondFactorFromDefaultLoginPolicy(SecondFactor) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/policies/login/secondfactors/{second_factor}"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc GetDefaultLoginPolicyMultiFactors(google.protobuf.Empty) returns (MultiFactorsResult) {
option (google.api.http) = {
get: "/policies/login/multifactors/_search"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.read"
};
}
rpc AddMultiFactorToDefaultLoginPolicy(MultiFactor) returns (MultiFactor) {
option (google.api.http) = {
post: "/policies/login/multifactors"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc RemoveMultiFactorFromDefaultLoginPolicy(MultiFactor) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/policies/login/multifactors/{multi_factor}"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc GetDefaultPasswordComplexityPolicy(google.protobuf.Empty) returns (DefaultPasswordComplexityPolicyView) {
option (google.api.http) = {
get: "/policies/password/complexity"
@@ -949,12 +1011,14 @@ message DefaultLoginPolicy {
bool allow_external_idp = 3;
google.protobuf.Timestamp creation_date = 4;
google.protobuf.Timestamp change_date = 5;
bool force_mfa = 6;
}
message DefaultLoginPolicyRequest {
bool allow_username_password = 1;
bool allow_register = 2;
bool allow_external_idp = 3;
bool force_mfa = 4;
}
message IdpProviderID {
@@ -967,6 +1031,7 @@ message DefaultLoginPolicyView {
bool allow_external_idp = 3;
google.protobuf.Timestamp creation_date = 4;
google.protobuf.Timestamp change_date = 5;
bool force_mfa = 6;
}
message IdpProviderView {
@@ -995,6 +1060,33 @@ message IdpProviderSearchRequest {
uint64 limit = 2;
}
message SecondFactorsResult {
repeated SecondFactorType second_factors = 1;
}
message SecondFactor {
SecondFactorType second_factor = 1;
}
enum SecondFactorType {
SECONDFACTORTYPE_UNSPECIFIED = 0;
SECONDFACTORTYPE_OTP = 1;
SECONDFACTORTYPE_U2F = 2;
}
message MultiFactorsResult {
repeated MultiFactorType multi_factors = 1;
}
message MultiFactor {
MultiFactorType multi_factor = 1;
}
enum MultiFactorType {
MULTIFACTORTYPE_UNSPECIFIED = 0;
MULTIFACTORTYPE_U2F_WITH_PIN = 1;
}
message DefaultPasswordComplexityPolicy {
uint64 min_length = 1;
bool has_uppercase = 2;

View File

@@ -609,6 +609,36 @@ var ManagementService_AuthMethods = authz.MethodMapping{
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/GetLoginPolicySecondFactors": authz.Option{
Permission: "iam.policy.read",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/AddSecondFactorToLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/RemoveSecondFactorFromLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/GetLoginPolicyMultiFactors": authz.Option{
Permission: "iam.policy.read",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/AddMultiFactorToLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/RemoveMultiFactorFromLoginPolicy": authz.Option{
Permission: "iam.policy.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/GetPasswordComplexityPolicy": authz.Option{
Permission: "policy.read",
CheckParam: "",

File diff suppressed because it is too large Load Diff

View File

@@ -7416,6 +7416,230 @@ func local_request_ManagementService_RemoveIdpProviderFromLoginPolicy_0(ctx cont
}
func request_ManagementService_GetLoginPolicySecondFactors_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := client.GetLoginPolicySecondFactors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_GetLoginPolicySecondFactors_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := server.GetLoginPolicySecondFactors(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_AddSecondFactorToLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SecondFactor
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.AddSecondFactorToLoginPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_AddSecondFactorToLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SecondFactor
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.AddSecondFactorToLoginPolicy(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_RemoveSecondFactorFromLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SecondFactor
var metadata runtime.ServerMetadata
var (
val string
e int32
ok bool
err error
_ = err
)
val, ok = pathParams["second_factor"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "second_factor")
}
e, err = runtime.Enum(val, SecondFactorType_value)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "second_factor", err)
}
protoReq.SecondFactor = SecondFactorType(e)
msg, err := client.RemoveSecondFactorFromLoginPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_RemoveSecondFactorFromLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SecondFactor
var metadata runtime.ServerMetadata
var (
val string
e int32
ok bool
err error
_ = err
)
val, ok = pathParams["second_factor"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "second_factor")
}
e, err = runtime.Enum(val, SecondFactorType_value)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "second_factor", err)
}
protoReq.SecondFactor = SecondFactorType(e)
msg, err := server.RemoveSecondFactorFromLoginPolicy(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_GetLoginPolicyMultiFactors_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := client.GetLoginPolicyMultiFactors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_GetLoginPolicyMultiFactors_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
msg, err := server.GetLoginPolicyMultiFactors(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_AddMultiFactorToLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiFactor
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.AddMultiFactorToLoginPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_AddMultiFactorToLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiFactor
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.AddMultiFactorToLoginPolicy(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_RemoveMultiFactorFromLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiFactor
var metadata runtime.ServerMetadata
var (
val string
e int32
ok bool
err error
_ = err
)
val, ok = pathParams["multi_factor"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "multi_factor")
}
e, err = runtime.Enum(val, MultiFactorType_value)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "multi_factor", err)
}
protoReq.MultiFactor = MultiFactorType(e)
msg, err := client.RemoveMultiFactorFromLoginPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ManagementService_RemoveMultiFactorFromLoginPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiFactor
var metadata runtime.ServerMetadata
var (
val string
e int32
ok bool
err error
_ = err
)
val, ok = pathParams["multi_factor"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "multi_factor")
}
e, err = runtime.Enum(val, MultiFactorType_value)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "multi_factor", err)
}
protoReq.MultiFactor = MultiFactorType(e)
msg, err := server.RemoveMultiFactorFromLoginPolicy(ctx, &protoReq)
return msg, metadata, err
}
func request_ManagementService_GetPasswordComplexityPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq empty.Empty
var metadata runtime.ServerMetadata
@@ -10247,6 +10471,126 @@ func RegisterManagementServiceHandlerServer(ctx context.Context, mux *runtime.Se
})
mux.Handle("GET", pattern_ManagementService_GetLoginPolicySecondFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_GetLoginPolicySecondFactors_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_GetLoginPolicySecondFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ManagementService_AddSecondFactorToLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_AddSecondFactorToLoginPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_AddSecondFactorToLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_RemoveSecondFactorFromLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_RemoveSecondFactorFromLoginPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_RemoveSecondFactorFromLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ManagementService_GetLoginPolicyMultiFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_GetLoginPolicyMultiFactors_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_GetLoginPolicyMultiFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ManagementService_AddMultiFactorToLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_AddMultiFactorToLoginPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_AddMultiFactorToLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_RemoveMultiFactorFromLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ManagementService_RemoveMultiFactorFromLoginPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_RemoveMultiFactorFromLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ManagementService_GetPasswordComplexityPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -13048,6 +13392,126 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se
})
mux.Handle("GET", pattern_ManagementService_GetLoginPolicySecondFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_GetLoginPolicySecondFactors_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_GetLoginPolicySecondFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ManagementService_AddSecondFactorToLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_AddSecondFactorToLoginPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_AddSecondFactorToLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_RemoveSecondFactorFromLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_RemoveSecondFactorFromLoginPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_RemoveSecondFactorFromLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ManagementService_GetLoginPolicyMultiFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_GetLoginPolicyMultiFactors_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_GetLoginPolicyMultiFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ManagementService_AddMultiFactorToLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_AddMultiFactorToLoginPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_AddMultiFactorToLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_RemoveMultiFactorFromLoginPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_RemoveMultiFactorFromLoginPolicy_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_RemoveMultiFactorFromLoginPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ManagementService_GetPasswordComplexityPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -13598,6 +14062,18 @@ var (
pattern_ManagementService_RemoveIdpProviderFromLoginPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"orgs", "me", "policies", "login", "idpproviders", "idp_config_id"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_GetLoginPolicySecondFactors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"orgs", "me", "policies", "login", "secondfactors", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_AddSecondFactorToLoginPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"orgs", "me", "policies", "login", "secondfactors"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_RemoveSecondFactorFromLoginPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"orgs", "me", "policies", "login", "secondfactors", "second_factor"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_GetLoginPolicyMultiFactors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"orgs", "me", "policies", "login", "multifactors", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_AddMultiFactorToLoginPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"orgs", "me", "policies", "login", "multifactors"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_RemoveMultiFactorFromLoginPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"orgs", "me", "policies", "login", "multifactors", "multi_factor"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_GetPasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"orgs", "me", "policies", "password", "complexity"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ManagementService_GetDefaultPasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"orgs", "default", "policies", "password", "complexity"}, "", runtime.AssumeColonVerbOpt(true)))
@@ -13876,6 +14352,18 @@ var (
forward_ManagementService_RemoveIdpProviderFromLoginPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_GetLoginPolicySecondFactors_0 = runtime.ForwardResponseMessage
forward_ManagementService_AddSecondFactorToLoginPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_RemoveSecondFactorFromLoginPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_GetLoginPolicyMultiFactors_0 = runtime.ForwardResponseMessage
forward_ManagementService_AddMultiFactorToLoginPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_RemoveMultiFactorFromLoginPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_GetPasswordComplexityPolicy_0 = runtime.ForwardResponseMessage
forward_ManagementService_GetDefaultPasswordComplexityPolicy_0 = runtime.ForwardResponseMessage

View File

@@ -4011,10 +4011,10 @@ var _ interface {
ErrorName() string
} = UpdateUserAddressRequestValidationError{}
// Validate checks the field values on MultiFactors with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *MultiFactors) Validate() error {
// Validate checks the field values on UserMultiFactors with the rules defined
// in the proto definition for this message. If any rules are violated, an
// error is returned.
func (m *UserMultiFactors) Validate() error {
if m == nil {
return nil
}
@@ -4024,7 +4024,7 @@ func (m *MultiFactors) Validate() error {
if v, ok := interface{}(item).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
return MultiFactorsValidationError{
return UserMultiFactorsValidationError{
field: fmt.Sprintf("Mfas[%v]", idx),
reason: "embedded message failed validation",
cause: err,
@@ -4037,9 +4037,9 @@ func (m *MultiFactors) Validate() error {
return nil
}
// MultiFactorsValidationError is the validation error returned by
// MultiFactors.Validate if the designated constraints aren't met.
type MultiFactorsValidationError struct {
// UserMultiFactorsValidationError is the validation error returned by
// UserMultiFactors.Validate if the designated constraints aren't met.
type UserMultiFactorsValidationError struct {
field string
reason string
cause error
@@ -4047,22 +4047,22 @@ type MultiFactorsValidationError struct {
}
// Field function returns field value.
func (e MultiFactorsValidationError) Field() string { return e.field }
func (e UserMultiFactorsValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorsValidationError) Reason() string { return e.reason }
func (e UserMultiFactorsValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorsValidationError) Cause() error { return e.cause }
func (e UserMultiFactorsValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorsValidationError) Key() bool { return e.key }
func (e UserMultiFactorsValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorsValidationError) ErrorName() string { return "MultiFactorsValidationError" }
func (e UserMultiFactorsValidationError) ErrorName() string { return "UserMultiFactorsValidationError" }
// Error satisfies the builtin error interface
func (e MultiFactorsValidationError) Error() string {
func (e UserMultiFactorsValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
@@ -4074,14 +4074,14 @@ func (e MultiFactorsValidationError) Error() string {
}
return fmt.Sprintf(
"invalid %sMultiFactors.%s: %s%s",
"invalid %sUserMultiFactors.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorsValidationError{}
var _ error = UserMultiFactorsValidationError{}
var _ interface {
Field() string
@@ -4089,12 +4089,12 @@ var _ interface {
Key() bool
Cause() error
ErrorName() string
} = MultiFactorsValidationError{}
} = UserMultiFactorsValidationError{}
// Validate checks the field values on MultiFactor with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *MultiFactor) Validate() error {
// Validate checks the field values on UserMultiFactor with the rules defined
// in the proto definition for this message. If any rules are violated, an
// error is returned.
func (m *UserMultiFactor) Validate() error {
if m == nil {
return nil
}
@@ -4106,9 +4106,9 @@ func (m *MultiFactor) Validate() error {
return nil
}
// MultiFactorValidationError is the validation error returned by
// MultiFactor.Validate if the designated constraints aren't met.
type MultiFactorValidationError struct {
// UserMultiFactorValidationError is the validation error returned by
// UserMultiFactor.Validate if the designated constraints aren't met.
type UserMultiFactorValidationError struct {
field string
reason string
cause error
@@ -4116,22 +4116,22 @@ type MultiFactorValidationError struct {
}
// Field function returns field value.
func (e MultiFactorValidationError) Field() string { return e.field }
func (e UserMultiFactorValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorValidationError) Reason() string { return e.reason }
func (e UserMultiFactorValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorValidationError) Cause() error { return e.cause }
func (e UserMultiFactorValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorValidationError) Key() bool { return e.key }
func (e UserMultiFactorValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorValidationError) ErrorName() string { return "MultiFactorValidationError" }
func (e UserMultiFactorValidationError) ErrorName() string { return "UserMultiFactorValidationError" }
// Error satisfies the builtin error interface
func (e MultiFactorValidationError) Error() string {
func (e UserMultiFactorValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
@@ -4143,14 +4143,14 @@ func (e MultiFactorValidationError) Error() string {
}
return fmt.Sprintf(
"invalid %sMultiFactor.%s: %s%s",
"invalid %sUserMultiFactor.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorValidationError{}
var _ error = UserMultiFactorValidationError{}
var _ interface {
Field() string
@@ -4158,7 +4158,7 @@ var _ interface {
Key() bool
Cause() error
ErrorName() string
} = MultiFactorValidationError{}
} = UserMultiFactorValidationError{}
// Validate checks the field values on PasswordRequest with the rules defined
// in the proto definition for this message. If any rules are violated, an
@@ -13383,6 +13383,8 @@ func (m *LoginPolicy) Validate() error {
}
}
// no validation rules for ForceMfa
return nil
}
@@ -13454,6 +13456,8 @@ func (m *LoginPolicyRequest) Validate() error {
// no validation rules for AllowExternalIdp
// no validation rules for ForceMfa
return nil
}
@@ -13773,6 +13777,8 @@ func (m *LoginPolicyView) Validate() error {
}
}
// no validation rules for ForceMfa
return nil
}
@@ -14413,6 +14419,274 @@ var _ interface {
ErrorName() string
} = ExternalIDPRemoveRequestValidationError{}
// Validate checks the field values on SecondFactorsResult with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
func (m *SecondFactorsResult) Validate() error {
if m == nil {
return nil
}
return nil
}
// SecondFactorsResultValidationError is the validation error returned by
// SecondFactorsResult.Validate if the designated constraints aren't met.
type SecondFactorsResultValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e SecondFactorsResultValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e SecondFactorsResultValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e SecondFactorsResultValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e SecondFactorsResultValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e SecondFactorsResultValidationError) ErrorName() string {
return "SecondFactorsResultValidationError"
}
// Error satisfies the builtin error interface
func (e SecondFactorsResultValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sSecondFactorsResult.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = SecondFactorsResultValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = SecondFactorsResultValidationError{}
// Validate checks the field values on SecondFactor with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *SecondFactor) Validate() error {
if m == nil {
return nil
}
// no validation rules for SecondFactor
return nil
}
// SecondFactorValidationError is the validation error returned by
// SecondFactor.Validate if the designated constraints aren't met.
type SecondFactorValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e SecondFactorValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e SecondFactorValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e SecondFactorValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e SecondFactorValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e SecondFactorValidationError) ErrorName() string { return "SecondFactorValidationError" }
// Error satisfies the builtin error interface
func (e SecondFactorValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sSecondFactor.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = SecondFactorValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = SecondFactorValidationError{}
// Validate checks the field values on MultiFactorsResult with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.
func (m *MultiFactorsResult) Validate() error {
if m == nil {
return nil
}
return nil
}
// MultiFactorsResultValidationError is the validation error returned by
// MultiFactorsResult.Validate if the designated constraints aren't met.
type MultiFactorsResultValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e MultiFactorsResultValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorsResultValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorsResultValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorsResultValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorsResultValidationError) ErrorName() string {
return "MultiFactorsResultValidationError"
}
// Error satisfies the builtin error interface
func (e MultiFactorsResultValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sMultiFactorsResult.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorsResultValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = MultiFactorsResultValidationError{}
// Validate checks the field values on MultiFactor with the rules defined in
// the proto definition for this message. If any rules are violated, an error
// is returned.
func (m *MultiFactor) Validate() error {
if m == nil {
return nil
}
// no validation rules for MultiFactor
return nil
}
// MultiFactorValidationError is the validation error returned by
// MultiFactor.Validate if the designated constraints aren't met.
type MultiFactorValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e MultiFactorValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e MultiFactorValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e MultiFactorValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e MultiFactorValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e MultiFactorValidationError) ErrorName() string { return "MultiFactorValidationError" }
// Error satisfies the builtin error interface
func (e MultiFactorValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sMultiFactor.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = MultiFactorValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = MultiFactorValidationError{}
// Validate checks the field values on PasswordComplexityPolicy with the rules
// defined in the proto definition for this message. If any rules are
// violated, an error is returned.

View File

@@ -1223,6 +1223,183 @@
]
}
},
"/orgs/me/policies/login/multifactors": {
"post": {
"operationId": "ManagementService_AddMultiFactorToLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1MultiFactor"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1MultiFactor"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/login/multifactors/_search": {
"get": {
"operationId": "ManagementService_GetLoginPolicyMultiFactors",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1MultiFactorsResult"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/login/multifactors/{multi_factor}": {
"delete": {
"operationId": "ManagementService_RemoveMultiFactorFromLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "multi_factor",
"in": "path",
"required": true,
"type": "string",
"enum": [
"MULTIFACTORTYPE_UNSPECIFIED",
"MULTIFACTORTYPE_U2F_WITH_PIN"
]
}
],
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/login/secondfactors": {
"post": {
"operationId": "ManagementService_AddSecondFactorToLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1SecondFactor"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1SecondFactor"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/login/secondfactors/_search": {
"get": {
"operationId": "ManagementService_GetLoginPolicySecondFactors",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1SecondFactorsResult"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/login/secondfactors/{second_factor}": {
"delete": {
"operationId": "ManagementService_RemoveSecondFactorFromLoginPolicy",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "second_factor",
"in": "path",
"required": true,
"type": "string",
"enum": [
"SECONDFACTORTYPE_UNSPECIFIED",
"SECONDFACTORTYPE_OTP",
"SECONDFACTORTYPE_U2F"
]
}
],
"tags": [
"ManagementService"
]
}
},
"/orgs/me/policies/password/age": {
"get": {
"operationId": "ManagementService_GetPasswordAgePolicy",
@@ -3808,7 +3985,7 @@
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1MultiFactors"
"$ref": "#/definitions/v1UserMultiFactors"
}
},
"default": {
@@ -5691,6 +5868,10 @@
"change_date": {
"type": "string",
"format": "date-time"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -5708,6 +5889,10 @@
"allow_external_idp": {
"type": "boolean",
"format": "boolean"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -5737,6 +5922,10 @@
"change_date": {
"type": "string",
"format": "date-time"
},
"force_mfa": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -5880,21 +6069,26 @@
"v1MultiFactor": {
"type": "object",
"properties": {
"type": {
"$ref": "#/definitions/v1MfaType"
},
"state": {
"$ref": "#/definitions/v1MFAState"
"multi_factor": {
"$ref": "#/definitions/v1MultiFactorType"
}
}
},
"v1MultiFactors": {
"v1MultiFactorType": {
"type": "string",
"enum": [
"MULTIFACTORTYPE_UNSPECIFIED",
"MULTIFACTORTYPE_U2F_WITH_PIN"
],
"default": "MULTIFACTORTYPE_UNSPECIFIED"
},
"v1MultiFactorsResult": {
"type": "object",
"properties": {
"mfas": {
"multi_factors": {
"type": "array",
"items": {
"$ref": "#/definitions/v1MultiFactor"
"$ref": "#/definitions/v1MultiFactorType"
}
}
}
@@ -7905,6 +8099,34 @@
],
"default": "SEARCHMETHOD_EQUALS"
},
"v1SecondFactor": {
"type": "object",
"properties": {
"second_factor": {
"$ref": "#/definitions/v1SecondFactorType"
}
}
},
"v1SecondFactorType": {
"type": "string",
"enum": [
"SECONDFACTORTYPE_UNSPECIFIED",
"SECONDFACTORTYPE_OTP",
"SECONDFACTORTYPE_U2F"
],
"default": "SECONDFACTORTYPE_UNSPECIFIED"
},
"v1SecondFactorsResult": {
"type": "object",
"properties": {
"second_factors": {
"type": "array",
"items": {
"$ref": "#/definitions/v1SecondFactorType"
}
}
}
},
"v1SetPasswordNotificationRequest": {
"type": "object",
"properties": {
@@ -8522,6 +8744,28 @@
}
}
},
"v1UserMultiFactor": {
"type": "object",
"properties": {
"type": {
"$ref": "#/definitions/v1MfaType"
},
"state": {
"$ref": "#/definitions/v1MFAState"
}
}
},
"v1UserMultiFactors": {
"type": "object",
"properties": {
"mfas": {
"type": "array",
"items": {
"$ref": "#/definitions/v1UserMultiFactor"
}
}
}
},
"v1UserPhone": {
"type": "object",
"properties": {

View File

@@ -77,6 +77,26 @@ func (mr *MockManagementServiceClientMockRecorder) AddMachineKey(arg0, arg1 inte
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMachineKey", reflect.TypeOf((*MockManagementServiceClient)(nil).AddMachineKey), varargs...)
}
// AddMultiFactorToLoginPolicy mocks base method
func (m *MockManagementServiceClient) AddMultiFactorToLoginPolicy(arg0 context.Context, arg1 *management.MultiFactor, arg2 ...grpc.CallOption) (*management.MultiFactor, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddMultiFactorToLoginPolicy", varargs...)
ret0, _ := ret[0].(*management.MultiFactor)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddMultiFactorToLoginPolicy indicates an expected call of AddMultiFactorToLoginPolicy
func (mr *MockManagementServiceClientMockRecorder) AddMultiFactorToLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMultiFactorToLoginPolicy", reflect.TypeOf((*MockManagementServiceClient)(nil).AddMultiFactorToLoginPolicy), varargs...)
}
// AddMyOrgDomain mocks base method
func (m *MockManagementServiceClient) AddMyOrgDomain(arg0 context.Context, arg1 *management.AddOrgDomainRequest, arg2 ...grpc.CallOption) (*management.OrgDomain, error) {
m.ctrl.T.Helper()
@@ -177,6 +197,26 @@ func (mr *MockManagementServiceClientMockRecorder) AddProjectRole(arg0, arg1 int
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddProjectRole", reflect.TypeOf((*MockManagementServiceClient)(nil).AddProjectRole), varargs...)
}
// AddSecondFactorToLoginPolicy mocks base method
func (m *MockManagementServiceClient) AddSecondFactorToLoginPolicy(arg0 context.Context, arg1 *management.SecondFactor, arg2 ...grpc.CallOption) (*management.SecondFactor, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddSecondFactorToLoginPolicy", varargs...)
ret0, _ := ret[0].(*management.SecondFactor)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddSecondFactorToLoginPolicy indicates an expected call of AddSecondFactorToLoginPolicy
func (mr *MockManagementServiceClientMockRecorder) AddSecondFactorToLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSecondFactorToLoginPolicy", reflect.TypeOf((*MockManagementServiceClient)(nil).AddSecondFactorToLoginPolicy), varargs...)
}
// ApplicationByID mocks base method
func (m *MockManagementServiceClient) ApplicationByID(arg0 context.Context, arg1 *management.ApplicationID, arg2 ...grpc.CallOption) (*management.ApplicationView, error) {
m.ctrl.T.Helper()
@@ -977,6 +1017,46 @@ func (mr *MockManagementServiceClientMockRecorder) GetLoginPolicyIdpProviders(ar
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLoginPolicyIdpProviders", reflect.TypeOf((*MockManagementServiceClient)(nil).GetLoginPolicyIdpProviders), varargs...)
}
// GetLoginPolicyMultiFactors mocks base method
func (m *MockManagementServiceClient) GetLoginPolicyMultiFactors(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*management.MultiFactorsResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetLoginPolicyMultiFactors", varargs...)
ret0, _ := ret[0].(*management.MultiFactorsResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetLoginPolicyMultiFactors indicates an expected call of GetLoginPolicyMultiFactors
func (mr *MockManagementServiceClientMockRecorder) GetLoginPolicyMultiFactors(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLoginPolicyMultiFactors", reflect.TypeOf((*MockManagementServiceClient)(nil).GetLoginPolicyMultiFactors), varargs...)
}
// GetLoginPolicySecondFactors mocks base method
func (m *MockManagementServiceClient) GetLoginPolicySecondFactors(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*management.SecondFactorsResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetLoginPolicySecondFactors", varargs...)
ret0, _ := ret[0].(*management.SecondFactorsResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetLoginPolicySecondFactors indicates an expected call of GetLoginPolicySecondFactors
func (mr *MockManagementServiceClientMockRecorder) GetLoginPolicySecondFactors(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLoginPolicySecondFactors", reflect.TypeOf((*MockManagementServiceClient)(nil).GetLoginPolicySecondFactors), varargs...)
}
// GetMachineKey mocks base method
func (m *MockManagementServiceClient) GetMachineKey(arg0 context.Context, arg1 *management.MachineKeyIDRequest, arg2 ...grpc.CallOption) (*management.MachineKeyView, error) {
m.ctrl.T.Helper()
@@ -1258,14 +1338,14 @@ func (mr *MockManagementServiceClientMockRecorder) GetUserEmail(arg0, arg1 inter
}
// GetUserMfas mocks base method
func (m *MockManagementServiceClient) GetUserMfas(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.MultiFactors, error) {
func (m *MockManagementServiceClient) GetUserMfas(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserMultiFactors, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetUserMfas", varargs...)
ret0, _ := ret[0].(*management.MultiFactors)
ret0, _ := ret[0].(*management.UserMultiFactors)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -1777,6 +1857,26 @@ func (mr *MockManagementServiceClientMockRecorder) RemoveLoginPolicy(arg0, arg1
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveLoginPolicy", reflect.TypeOf((*MockManagementServiceClient)(nil).RemoveLoginPolicy), varargs...)
}
// RemoveMultiFactorFromLoginPolicy mocks base method
func (m *MockManagementServiceClient) RemoveMultiFactorFromLoginPolicy(arg0 context.Context, arg1 *management.MultiFactor, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "RemoveMultiFactorFromLoginPolicy", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RemoveMultiFactorFromLoginPolicy indicates an expected call of RemoveMultiFactorFromLoginPolicy
func (mr *MockManagementServiceClientMockRecorder) RemoveMultiFactorFromLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMultiFactorFromLoginPolicy", reflect.TypeOf((*MockManagementServiceClient)(nil).RemoveMultiFactorFromLoginPolicy), varargs...)
}
// RemoveMyOrgDomain mocks base method
func (m *MockManagementServiceClient) RemoveMyOrgDomain(arg0 context.Context, arg1 *management.RemoveOrgDomainRequest, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
@@ -1977,6 +2077,26 @@ func (mr *MockManagementServiceClientMockRecorder) RemoveProjectRole(arg0, arg1
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveProjectRole", reflect.TypeOf((*MockManagementServiceClient)(nil).RemoveProjectRole), varargs...)
}
// RemoveSecondFactorFromLoginPolicy mocks base method
func (m *MockManagementServiceClient) RemoveSecondFactorFromLoginPolicy(arg0 context.Context, arg1 *management.SecondFactor, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "RemoveSecondFactorFromLoginPolicy", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RemoveSecondFactorFromLoginPolicy indicates an expected call of RemoveSecondFactorFromLoginPolicy
func (mr *MockManagementServiceClientMockRecorder) RemoveSecondFactorFromLoginPolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSecondFactorFromLoginPolicy", reflect.TypeOf((*MockManagementServiceClient)(nil).RemoveSecondFactorFromLoginPolicy), varargs...)
}
// RemoveUserGrant mocks base method
func (m *MockManagementServiceClient) RemoveUserGrant(arg0 context.Context, arg1 *management.UserGrantID, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()

View File

@@ -390,7 +390,7 @@ rpc GetUserByID(UserID) returns (UserView) {
};
}
rpc GetUserMfas(UserID) returns (MultiFactors) {
rpc GetUserMfas(UserID) returns (UserMultiFactors) {
option (google.api.http) = {
get: "/users/{id}/mfas"
};
@@ -1363,6 +1363,68 @@ rpc GetUserByID(UserID) returns (UserView) {
};
}
rpc GetLoginPolicySecondFactors(google.protobuf.Empty) returns (SecondFactorsResult) {
option (google.api.http) = {
get: "/orgs/me/policies/login/secondfactors/_search"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.read"
};
}
rpc AddSecondFactorToLoginPolicy(SecondFactor) returns (SecondFactor) {
option (google.api.http) = {
post: "/orgs/me/policies/login/secondfactors"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc RemoveSecondFactorFromLoginPolicy(SecondFactor) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/orgs/me/policies/login/secondfactors/{second_factor}"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc GetLoginPolicyMultiFactors(google.protobuf.Empty) returns (MultiFactorsResult) {
option (google.api.http) = {
get: "/orgs/me/policies/login/multifactors/_search"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.read"
};
}
rpc AddMultiFactorToLoginPolicy(MultiFactor) returns (MultiFactor) {
option (google.api.http) = {
post: "/orgs/me/policies/login/multifactors"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc RemoveMultiFactorFromLoginPolicy(MultiFactor) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/orgs/me/policies/login/multifactors/{multi_factor}"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "iam.policy.write"
};
}
rpc GetPasswordComplexityPolicy(google.protobuf.Empty) returns (PasswordComplexityPolicyView) {
option (google.api.http) = {
get: "/orgs/me/policies/password/complexity"
@@ -1950,11 +2012,11 @@ message UpdateUserAddressRequest {
string street_address = 6 [(validate.rules).string = {max_len: 200}];
}
message MultiFactors {
repeated MultiFactor mfas = 1;
message UserMultiFactors {
repeated UserMultiFactor mfas = 1;
}
message MultiFactor {
message UserMultiFactor {
MfaType type = 1;
MFAState state = 2;
}
@@ -2980,12 +3042,14 @@ message LoginPolicy {
bool allow_external_idp = 3;
google.protobuf.Timestamp creation_date = 4;
google.protobuf.Timestamp change_date = 5;
bool force_mfa = 6;
}
message LoginPolicyRequest {
bool allow_username_password = 1;
bool allow_register = 2;
bool allow_external_idp = 3;
bool force_mfa = 4;
}
message IdpProviderID {
@@ -3009,6 +3073,7 @@ message LoginPolicyView {
bool allow_external_idp = 4;
google.protobuf.Timestamp creation_date = 5;
google.protobuf.Timestamp change_date = 6;
bool force_mfa = 7;
}
message IdpProviderView {
@@ -3081,6 +3146,33 @@ message ExternalIDPRemoveRequest {
string external_user_id = 3;
}
message SecondFactorsResult {
repeated SecondFactorType second_factors = 1;
}
message SecondFactor {
SecondFactorType second_factor = 1;
}
enum SecondFactorType {
SECONDFACTORTYPE_UNSPECIFIED = 0;
SECONDFACTORTYPE_OTP = 1;
SECONDFACTORTYPE_U2F = 2;
}
message MultiFactorsResult {
repeated MultiFactorType multi_factors = 1;
}
message MultiFactor {
MultiFactorType multi_factor = 1;
}
enum MultiFactorType {
MULTIFACTORTYPE_UNSPECIFIED = 0;
MULTIFACTORTYPE_U2F_WITH_PIN = 1;
}
message PasswordComplexityPolicy {
uint64 min_length = 1;
bool has_lowercase = 2;