mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-29 23:00:49 +00:00
feat: Login verification lifetimes (#3190)
* feat: add login check lifetimes to login policy * feat: org features test * feat: read lifetimes from loginpolicy
This commit is contained in:
parent
7d235e3eed
commit
f05d4063bf
@ -1514,7 +1514,7 @@ This is an empty request
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| sid | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| token | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| from | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| sender_number | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
@ -3593,6 +3593,11 @@ This is an empty request
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
| password_check_lifetime | google.protobuf.Duration | - | |
|
||||
| external_login_check_lifetime | google.protobuf.Duration | - | |
|
||||
| mfa_init_skip_lifetime | google.protobuf.Duration | - | |
|
||||
| second_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
|
||||
|
||||
|
||||
@ -3710,7 +3715,7 @@ This is an empty request
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| sid | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| from | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| sender_number | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
@ -3036,6 +3036,11 @@ This is an empty request
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
| password_check_lifetime | google.protobuf.Duration | - | |
|
||||
| external_login_check_lifetime | google.protobuf.Duration | - | |
|
||||
| mfa_init_skip_lifetime | google.protobuf.Duration | - | |
|
||||
| second_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
|
||||
|
||||
|
||||
@ -7751,6 +7756,11 @@ This is an empty request
|
||||
| force_mfa | bool | - | |
|
||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||
| hide_password_reset | bool | - | |
|
||||
| password_check_lifetime | google.protobuf.Duration | - | |
|
||||
| external_login_check_lifetime | google.protobuf.Duration | - | |
|
||||
| mfa_init_skip_lifetime | google.protobuf.Duration | - | |
|
||||
| second_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -63,6 +63,11 @@ title: zitadel/policy.proto
|
||||
| passwordless_type | PasswordlessType | - | |
|
||||
| is_default | bool | - | |
|
||||
| hide_password_reset | bool | - | |
|
||||
| password_check_lifetime | google.protobuf.Duration | - | |
|
||||
| external_login_check_lifetime | google.protobuf.Duration | - | |
|
||||
| mfa_init_skip_lifetime | google.protobuf.Duration | - | |
|
||||
| second_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
| multi_factor_check_lifetime | google.protobuf.Duration | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -10,12 +10,17 @@ import (
|
||||
|
||||
func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.LoginPolicy {
|
||||
return &domain.LoginPolicy{
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,23 +10,33 @@ import (
|
||||
|
||||
func addLoginPolicyToDomain(p *mgmt_pb.AddCustomLoginPolicyRequest) *domain.LoginPolicy {
|
||||
return &domain.LoginPolicy{
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||
}
|
||||
}
|
||||
|
||||
func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domain.LoginPolicy {
|
||||
return &domain.LoginPolicy{
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
||||
AllowRegister: p.AllowRegister,
|
||||
AllowExternalIDP: p.AllowExternalIdp,
|
||||
ForceMFA: p.ForceMfa,
|
||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||
HidePasswordReset: p.HidePasswordReset,
|
||||
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,18 +5,24 @@ import (
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/pkg/grpc/object"
|
||||
policy_pb "github.com/caos/zitadel/pkg/grpc/policy"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
timestamp_pb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func ModelLoginPolicyToPb(policy *query.LoginPolicy) *policy_pb.LoginPolicy {
|
||||
return &policy_pb.LoginPolicy{
|
||||
IsDefault: policy.IsDefault,
|
||||
AllowUsernamePassword: policy.AllowUsernamePassword,
|
||||
AllowRegister: policy.AllowRegister,
|
||||
AllowExternalIdp: policy.AllowExternalIDPs,
|
||||
ForceMfa: policy.ForceMFA,
|
||||
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
IsDefault: policy.IsDefault,
|
||||
AllowUsernamePassword: policy.AllowUsernamePassword,
|
||||
AllowRegister: policy.AllowRegister,
|
||||
AllowExternalIdp: policy.AllowExternalIDPs,
|
||||
ForceMfa: policy.ForceMFA,
|
||||
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
|
||||
HidePasswordReset: policy.HidePasswordReset,
|
||||
PasswordCheckLifetime: durationpb.New(policy.PasswordCheckLifetime),
|
||||
ExternalLoginCheckLifetime: durationpb.New(policy.ExternalLoginCheckLifetime),
|
||||
MfaInitSkipLifetime: durationpb.New(policy.MFAInitSkipLifetime),
|
||||
SecondFactorCheckLifetime: durationpb.New(policy.SecondFactorCheckLifetime),
|
||||
MultiFactorCheckLifetime: durationpb.New(policy.MultiFactorCheckLifetime),
|
||||
Details: &object.ObjectDetails{
|
||||
Sequence: policy.Sequence,
|
||||
CreationDate: timestamp_pb.New(policy.CreationDate),
|
||||
|
@ -50,12 +50,6 @@ type AuthRequestRepo struct {
|
||||
ApplicationProvider applicationProvider
|
||||
|
||||
IdGenerator id.Generator
|
||||
|
||||
PasswordCheckLifeTime time.Duration
|
||||
ExternalLoginCheckLifeTime time.Duration
|
||||
MFAInitSkippedLifeTime time.Duration
|
||||
SecondFactorCheckLifeTime time.Duration
|
||||
MultiFactorCheckLifeTime time.Duration
|
||||
}
|
||||
|
||||
type labelPolicyProvider interface {
|
||||
@ -761,7 +755,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
}
|
||||
|
||||
isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
|
||||
if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTimeMaxAge(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime, request) {
|
||||
if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTimeMaxAge(userSession.ExternalLoginVerification, request.LoginPolicy.ExternalLoginCheckLifetime, request) {
|
||||
selectedIDPConfigID := request.SelectedIDPConfigID
|
||||
if selectedIDPConfigID == "" {
|
||||
selectedIDPConfigID = userSession.SelectedIDPConfigID
|
||||
@ -858,7 +852,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use
|
||||
|
||||
var step domain.NextStep
|
||||
if request.LoginPolicy.PasswordlessType != domain.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() {
|
||||
if checkVerificationTimeMaxAge(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime, request) {
|
||||
if checkVerificationTimeMaxAge(userSession.PasswordlessVerification, request.LoginPolicy.MultiFactorCheckLifetime, request) {
|
||||
request.AuthTime = userSession.PasswordlessVerification
|
||||
return nil
|
||||
}
|
||||
@ -875,7 +869,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use
|
||||
return &domain.InitPasswordStep{}
|
||||
}
|
||||
|
||||
if checkVerificationTimeMaxAge(userSession.PasswordVerification, repo.PasswordCheckLifeTime, request) {
|
||||
if checkVerificationTimeMaxAge(userSession.PasswordVerification, request.LoginPolicy.PasswordCheckLifetime, request) {
|
||||
request.PasswordVerified = true
|
||||
request.AuthTime = userSession.PasswordVerification
|
||||
return nil
|
||||
@ -890,7 +884,7 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
|
||||
mfaLevel := request.MFALevel()
|
||||
allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy)
|
||||
promptRequired := (model.MFALevelToDomain(user.MFAMaxSetUp) < mfaLevel) || (len(allowedProviders) == 0 && required)
|
||||
if promptRequired || !repo.mfaSkippedOrSetUp(user) {
|
||||
if promptRequired || !repo.mfaSkippedOrSetUp(user, request) {
|
||||
types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy)
|
||||
if promptRequired && len(types) == 0 {
|
||||
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
|
||||
@ -912,14 +906,14 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
|
||||
}
|
||||
fallthrough
|
||||
case domain.MFALevelSecondFactor:
|
||||
if checkVerificationTimeMaxAge(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime, request) {
|
||||
if checkVerificationTimeMaxAge(userSession.SecondFactorVerification, request.LoginPolicy.SecondFactorCheckLifetime, request) {
|
||||
request.MFAsVerified = append(request.MFAsVerified, model.MFATypeToDomain(userSession.SecondFactorVerificationType))
|
||||
request.AuthTime = userSession.SecondFactorVerification
|
||||
return nil, true, nil
|
||||
}
|
||||
fallthrough
|
||||
case domain.MFALevelMultiFactor:
|
||||
if checkVerificationTimeMaxAge(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime, request) {
|
||||
if checkVerificationTimeMaxAge(userSession.MultiFactorVerification, request.LoginPolicy.MultiFactorCheckLifetime, request) {
|
||||
request.MFAsVerified = append(request.MFAsVerified, model.MFATypeToDomain(userSession.MultiFactorVerificationType))
|
||||
request.AuthTime = userSession.MultiFactorVerification
|
||||
return nil, true, nil
|
||||
@ -930,11 +924,11 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
|
||||
}, false, nil
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool {
|
||||
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, request *domain.AuthRequest) bool {
|
||||
if user.MFAMaxSetUp > model.MFALevelNotSetUp {
|
||||
return true
|
||||
}
|
||||
return checkVerificationTime(user.MFAInitSkipped, repo.MFAInitSkippedLifeTime)
|
||||
return checkVerificationTime(user.MFAInitSkipped, request.LoginPolicy.MFAInitSkipLifetime)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) getPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) {
|
||||
|
@ -252,22 +252,17 @@ func (m *mockApp) AppByOIDCClientID(ctx context.Context, id string) (*query.App,
|
||||
|
||||
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
type fields struct {
|
||||
AuthRequests *cache.AuthRequestCache
|
||||
View *view.View
|
||||
userSessionViewProvider userSessionViewProvider
|
||||
userViewProvider userViewProvider
|
||||
userEventProvider userEventProvider
|
||||
orgViewProvider orgViewProvider
|
||||
userGrantProvider userGrantProvider
|
||||
projectProvider projectProvider
|
||||
applicationProvider applicationProvider
|
||||
loginPolicyProvider loginPolicyViewProvider
|
||||
lockoutPolicyProvider lockoutPolicyViewProvider
|
||||
PasswordCheckLifeTime time.Duration
|
||||
ExternalLoginCheckLifeTime time.Duration
|
||||
MFAInitSkippedLifeTime time.Duration
|
||||
SecondFactorCheckLifeTime time.Duration
|
||||
MultiFactorCheckLifeTime time.Duration
|
||||
AuthRequests *cache.AuthRequestCache
|
||||
View *view.View
|
||||
userSessionViewProvider userSessionViewProvider
|
||||
userViewProvider userViewProvider
|
||||
userEventProvider userEventProvider
|
||||
orgViewProvider orgViewProvider
|
||||
userGrantProvider userGrantProvider
|
||||
projectProvider projectProvider
|
||||
applicationProvider applicationProvider
|
||||
loginPolicyProvider loginPolicyViewProvider
|
||||
lockoutPolicyProvider lockoutPolicyViewProvider
|
||||
}
|
||||
type args struct {
|
||||
request *domain.AuthRequest
|
||||
@ -570,14 +565,18 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userViewProvider: &mockViewUser{
|
||||
PasswordlessInitRequired: true,
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||
policy: &query.LockoutPolicy{
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessRegistrationPromptStep{}},
|
||||
@ -597,7 +596,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessStep{}},
|
||||
@ -618,7 +621,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||
[]domain.NextStep{&domain.PasswordlessStep{PasswordSet: true}},
|
||||
@ -644,14 +651,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
||||
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
||||
@ -692,10 +699,19 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
}}, false},
|
||||
[]domain.NextStep{&domain.ExternalLoginStep{SelectedIDPConfigID: "IDPConfigID"}},
|
||||
nil,
|
||||
},
|
||||
@ -715,23 +731,21 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
userGrantProvider: &mockUserGrants{},
|
||||
projectProvider: &mockProject{},
|
||||
applicationProvider: &mockApp{app: &query.App{OIDCConfig: &query.OIDCApp{AppType: domain.OIDCApplicationTypeWeb}}},
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{},
|
||||
},
|
||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||
policy: &query.LockoutPolicy{
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
ExternalLoginCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
false},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
@ -751,7 +765,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||
[]domain.NextStep{&domain.PasswordStep{}},
|
||||
@ -779,15 +797,16 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
ExternalLoginCheckLifetime: 10 * 24 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
nil,
|
||||
@ -811,14 +830,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||
@ -844,14 +863,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||
@ -878,16 +897,16 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
ExternalLoginCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||
@ -915,14 +934,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.ChangePasswordStep{}},
|
||||
@ -946,13 +965,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
||||
@ -977,13 +996,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.ChangePasswordStep{}, &domain.VerifyEMailStep{}},
|
||||
@ -1011,14 +1030,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
@ -1046,15 +1065,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
@ -1082,15 +1101,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.LoginSucceededStep{}, &domain.RedirectToCallbackStep{}},
|
||||
@ -1120,15 +1139,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.GrantRequiredStep{}},
|
||||
@ -1159,15 +1178,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
@ -1197,15 +1216,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.ProjectRequiredStep{}},
|
||||
@ -1236,15 +1255,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
Request: &domain.AuthRequestOIDC{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
}, true},
|
||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||
@ -1266,9 +1285,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
loginPolicyProvider: &mockLoginPolicy{
|
||||
policy: &query.LoginPolicy{
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -1299,8 +1322,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
@ -1308,7 +1329,9 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
LinkingUsers: []*domain.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||
},
|
||||
}, false},
|
||||
[]domain.NextStep{&domain.LinkUsersStep{}},
|
||||
@ -1318,22 +1341,17 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
repo := &AuthRequestRepo{
|
||||
AuthRequests: tt.fields.AuthRequests,
|
||||
View: tt.fields.View,
|
||||
UserSessionViewProvider: tt.fields.userSessionViewProvider,
|
||||
UserViewProvider: tt.fields.userViewProvider,
|
||||
UserEventProvider: tt.fields.userEventProvider,
|
||||
OrgViewProvider: tt.fields.orgViewProvider,
|
||||
UserGrantProvider: tt.fields.userGrantProvider,
|
||||
ProjectProvider: tt.fields.projectProvider,
|
||||
ApplicationProvider: tt.fields.applicationProvider,
|
||||
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
|
||||
LockoutPolicyViewProvider: tt.fields.lockoutPolicyProvider,
|
||||
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
|
||||
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
|
||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
||||
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
|
||||
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
|
||||
AuthRequests: tt.fields.AuthRequests,
|
||||
View: tt.fields.View,
|
||||
UserSessionViewProvider: tt.fields.userSessionViewProvider,
|
||||
UserViewProvider: tt.fields.userViewProvider,
|
||||
UserEventProvider: tt.fields.userEventProvider,
|
||||
OrgViewProvider: tt.fields.orgViewProvider,
|
||||
UserGrantProvider: tt.fields.userGrantProvider,
|
||||
ProjectProvider: tt.fields.projectProvider,
|
||||
ApplicationProvider: tt.fields.applicationProvider,
|
||||
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
|
||||
LockoutPolicyViewProvider: tt.fields.lockoutPolicyProvider,
|
||||
}
|
||||
got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn)
|
||||
if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) {
|
||||
@ -1346,11 +1364,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
type fields struct {
|
||||
MFAInitSkippedLifeTime time.Duration
|
||||
SecondFactorCheckLifeTime time.Duration
|
||||
MultiFactorCheckLifeTime time.Duration
|
||||
}
|
||||
type args struct {
|
||||
userSession *user_model.UserSessionView
|
||||
request *domain.AuthRequest
|
||||
@ -1358,7 +1371,6 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want domain.NextStep
|
||||
wantChecked bool
|
||||
@ -1377,13 +1389,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
//},
|
||||
{
|
||||
"not set up, forced by policy, no mfas configured, error",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
ForceMFA: true,
|
||||
ForceMFA: true,
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
@ -1398,12 +1408,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"not set up, no mfas configured, no prompt and true",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
HumanView: &user_model.HumanView{
|
||||
@ -1417,13 +1426,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"not set up, prompt and false",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
@ -1442,14 +1449,12 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"not set up, forced by org, true",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
ForceMFA: true,
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
ForceMFA: true,
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
@ -1469,12 +1474,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"not set up and skipped, true",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{},
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
HumanView: &user_model.HumanView{
|
||||
@ -1489,13 +1493,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"checked second factor, true",
|
||||
fields{
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
@ -1512,13 +1514,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"not checked, check and false",
|
||||
fields{
|
||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
||||
},
|
||||
args{
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||
},
|
||||
},
|
||||
user: &user_model.UserView{
|
||||
@ -1539,11 +1539,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
repo := &AuthRequestRepo{
|
||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
||||
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
|
||||
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
|
||||
}
|
||||
repo := &AuthRequestRepo{}
|
||||
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)
|
||||
@ -1562,7 +1558,8 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
|
||||
MFAInitSkippedLifeTime time.Duration
|
||||
}
|
||||
type args struct {
|
||||
user *user_model.UserView
|
||||
user *user_model.UserView
|
||||
request *domain.AuthRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -1574,51 +1571,58 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
|
||||
"mfa set up, true",
|
||||
fields{},
|
||||
args{
|
||||
&user_model.UserView{
|
||||
user: &user_model.UserView{
|
||||
HumanView: &user_model.HumanView{
|
||||
MFAMaxSetUp: model.MFALevelSecondFactor,
|
||||
},
|
||||
},
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"mfa skipped active, true",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
fields{},
|
||||
args{
|
||||
&user_model.UserView{
|
||||
user: &user_model.UserView{
|
||||
HumanView: &user_model.HumanView{
|
||||
MFAMaxSetUp: -1,
|
||||
MFAInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
|
||||
},
|
||||
},
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"mfa skipped inactive, false",
|
||||
fields{
|
||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
||||
},
|
||||
fields{},
|
||||
args{
|
||||
&user_model.UserView{
|
||||
user: &user_model.UserView{
|
||||
HumanView: &user_model.HumanView{
|
||||
MFAMaxSetUp: -1,
|
||||
MFAInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
|
||||
},
|
||||
},
|
||||
request: &domain.AuthRequest{
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
repo := &AuthRequestRepo{
|
||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
||||
}
|
||||
if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want {
|
||||
repo := &AuthRequestRepo{}
|
||||
if got := repo.mfaSkippedOrSetUp(tt.args.user, tt.args.request); got != tt.want {
|
||||
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -72,31 +72,26 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, command *command.Comma
|
||||
es,
|
||||
userRepo,
|
||||
eventstore.AuthRequestRepo{
|
||||
PrivacyPolicyProvider: queries,
|
||||
LabelPolicyProvider: queries,
|
||||
Command: command,
|
||||
Query: queries,
|
||||
OrgViewProvider: queries,
|
||||
AuthRequests: authReq,
|
||||
View: view,
|
||||
Eventstore: es,
|
||||
UserCodeAlg: userCrypto,
|
||||
UserSessionViewProvider: view,
|
||||
UserViewProvider: view,
|
||||
UserCommandProvider: command,
|
||||
UserEventProvider: &userRepo,
|
||||
IDPProviderViewProvider: view,
|
||||
LockoutPolicyViewProvider: queries,
|
||||
LoginPolicyViewProvider: queries,
|
||||
UserGrantProvider: queryView,
|
||||
ProjectProvider: queryView,
|
||||
ApplicationProvider: queries,
|
||||
IdGenerator: idGenerator,
|
||||
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck,
|
||||
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck,
|
||||
MFAInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MFAInitSkip,
|
||||
SecondFactorCheckLifeTime: systemDefaults.VerificationLifetimes.SecondFactorCheck,
|
||||
MultiFactorCheckLifeTime: systemDefaults.VerificationLifetimes.MultiFactorCheck,
|
||||
PrivacyPolicyProvider: queries,
|
||||
LabelPolicyProvider: queries,
|
||||
Command: command,
|
||||
Query: queries,
|
||||
OrgViewProvider: queries,
|
||||
AuthRequests: authReq,
|
||||
View: view,
|
||||
Eventstore: es,
|
||||
UserCodeAlg: userCrypto,
|
||||
UserSessionViewProvider: view,
|
||||
UserViewProvider: view,
|
||||
UserCommandProvider: command,
|
||||
UserEventProvider: &userRepo,
|
||||
IDPProviderViewProvider: view,
|
||||
LockoutPolicyViewProvider: queries,
|
||||
LoginPolicyViewProvider: queries,
|
||||
UserGrantProvider: queryView,
|
||||
ProjectProvider: queryView,
|
||||
ApplicationProvider: queries,
|
||||
IdGenerator: idGenerator,
|
||||
},
|
||||
eventstore.TokenRepo{
|
||||
View: view,
|
||||
|
@ -35,13 +35,18 @@ func memberWriteModelToMember(writeModel *MemberWriteModel) *domain.Member {
|
||||
|
||||
func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy {
|
||||
return &domain.LoginPolicy{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
AllowUsernamePassword: wm.AllowUserNamePassword,
|
||||
AllowRegister: wm.AllowRegister,
|
||||
AllowExternalIDP: wm.AllowExternalIDP,
|
||||
HidePasswordReset: wm.HidePasswordReset,
|
||||
ForceMFA: wm.ForceMFA,
|
||||
PasswordlessType: wm.PasswordlessType,
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
AllowUsernamePassword: wm.AllowUserNamePassword,
|
||||
AllowRegister: wm.AllowRegister,
|
||||
AllowExternalIDP: wm.AllowExternalIDP,
|
||||
HidePasswordReset: wm.HidePasswordReset,
|
||||
ForceMFA: wm.ForceMFA,
|
||||
PasswordlessType: wm.PasswordlessType,
|
||||
PasswordCheckLifetime: wm.PasswordCheckLifetime,
|
||||
ExternalLoginCheckLifetime: wm.ExternalLoginCheckLifetime,
|
||||
MFAInitSkipLifetime: wm.MFAInitSkipLifetime,
|
||||
SecondFactorCheckLifetime: wm.SecondFactorCheckLifetime,
|
||||
MultiFactorCheckLifetime: wm.MultiFactorCheckLifetime,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,19 @@ func (c *Commands) addDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
|
||||
}
|
||||
|
||||
return iam_repo.NewLoginPolicyAddedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType), nil
|
||||
return iam_repo.NewLoginPolicyAddedEvent(ctx,
|
||||
iamAgg,
|
||||
policy.AllowUsernamePassword,
|
||||
policy.AllowRegister,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType,
|
||||
policy.PasswordCheckLifetime,
|
||||
policy.ExternalLoginCheckLifetime,
|
||||
policy.MFAInitSkipLifetime,
|
||||
policy.SecondFactorCheckLifetime,
|
||||
policy.MultiFactorCheckLifetime), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
|
||||
@ -78,7 +90,19 @@ func (c *Commands) changeDefaultLoginPolicy(ctx context.Context, iamAgg *eventst
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx,
|
||||
iamAgg,
|
||||
policy.AllowUsernamePassword,
|
||||
policy.AllowRegister,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType,
|
||||
policy.PasswordCheckLifetime,
|
||||
policy.ExternalLoginCheckLifetime,
|
||||
policy.MFAInitSkipLifetime,
|
||||
policy.SecondFactorCheckLifetime,
|
||||
policy.MultiFactorCheckLifetime)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
@ -65,6 +66,11 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime time.Duration,
|
||||
) (*iam.LoginPolicyChangedEvent, bool) {
|
||||
|
||||
changes := make([]policy.LoginPolicyChanges, 0)
|
||||
@ -86,6 +92,21 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
||||
if wm.HidePasswordReset != hidePasswordReset {
|
||||
changes = append(changes, policy.ChangeHidePasswordReset(hidePasswordReset))
|
||||
}
|
||||
if wm.PasswordCheckLifetime != passwordCheckLifetime {
|
||||
changes = append(changes, policy.ChangePasswordCheckLifetime(passwordCheckLifetime))
|
||||
}
|
||||
if wm.ExternalLoginCheckLifetime != externalLoginCheckLifetime {
|
||||
changes = append(changes, policy.ChangeExternalLoginCheckLifetime(externalLoginCheckLifetime))
|
||||
}
|
||||
if wm.MFAInitSkipLifetime != mfaInitSkipLifetime {
|
||||
changes = append(changes, policy.ChangeMFAInitSkipLifetime(mfaInitSkipLifetime))
|
||||
}
|
||||
if wm.SecondFactorCheckLifetime != secondFactorCheckLifetime {
|
||||
changes = append(changes, policy.ChangeSecondFactorCheckLifetime(secondFactorCheckLifetime))
|
||||
}
|
||||
if wm.MultiFactorCheckLifetime != multiFactorCheckLifetime {
|
||||
changes = append(changes, policy.ChangeMultiFactorCheckLifetime(multiFactorCheckLifetime))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
@ -49,6 +50,11 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*1,
|
||||
time.Hour*1,
|
||||
time.Hour*1,
|
||||
time.Hour*1,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -83,6 +89,11 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
},
|
||||
@ -92,12 +103,17 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -106,12 +122,17 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
||||
AggregateID: "IAM",
|
||||
ResourceOwner: "IAM",
|
||||
},
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -187,6 +208,11 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -195,12 +221,17 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -222,13 +253,29 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newDefaultLoginPolicyChangedEvent(context.Background(), false, false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
newDefaultLoginPolicyChangedEvent(context.Background(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*10,
|
||||
time.Hour*20,
|
||||
time.Hour*30,
|
||||
time.Hour*40,
|
||||
time.Hour*50),
|
||||
),
|
||||
},
|
||||
),
|
||||
@ -237,12 +284,17 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 10,
|
||||
ExternalLoginCheckLifetime: time.Hour * 20,
|
||||
MFAInitSkipLifetime: time.Hour * 30,
|
||||
SecondFactorCheckLifetime: time.Hour * 40,
|
||||
MultiFactorCheckLifetime: time.Hour * 50,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -251,12 +303,17 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
||||
AggregateID: "IAM",
|
||||
ResourceOwner: "IAM",
|
||||
},
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 10,
|
||||
ExternalLoginCheckLifetime: time.Hour * 20,
|
||||
MFAInitSkipLifetime: time.Hour * 30,
|
||||
SecondFactorCheckLifetime: time.Hour * 40,
|
||||
MultiFactorCheckLifetime: time.Hour * 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -346,6 +403,11 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -377,6 +439,11 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -427,6 +494,11 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -557,6 +629,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -588,6 +665,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -632,6 +714,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -681,6 +768,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -738,6 +830,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1283,7 +1380,9 @@ func TestCommandSide_RemoveMultiFactorDefaultLoginPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, hidePasswordReset bool, passwordlessType domain.PasswordlessType) *iam.LoginPolicyChangedEvent {
|
||||
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordLifetime, externalLoginLifetime, mfaInitSkipLifetime, secondFactorLifetime, multiFactorLifetime time.Duration) *iam.LoginPolicyChangedEvent {
|
||||
event, _ := iam.NewLoginPolicyChangedEvent(ctx,
|
||||
&iam.NewAggregate().Aggregate,
|
||||
[]policy.LoginPolicyChanges{
|
||||
@ -1293,6 +1392,11 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow
|
||||
policy.ChangeAllowUserNamePassword(allowUsernamePassword),
|
||||
policy.ChangeHidePasswordReset(hidePasswordReset),
|
||||
policy.ChangePasswordlessType(passwordlessType),
|
||||
policy.ChangePasswordCheckLifetime(passwordLifetime),
|
||||
policy.ChangeExternalLoginCheckLifetime(externalLoginLifetime),
|
||||
policy.ChangeMFAInitSkipLifetime(mfaInitSkipLifetime),
|
||||
policy.ChangeSecondFactorCheckLifetime(secondFactorLifetime),
|
||||
policy.ChangeMultiFactorCheckLifetime(multiFactorLifetime),
|
||||
},
|
||||
)
|
||||
return event
|
||||
|
@ -241,7 +241,19 @@ func (c *Commands) setAllowedLoginPolicy(ctx context.Context, orgID string, feat
|
||||
if !features.LoginPolicyPasswordReset && defaultPolicy.HidePasswordReset != existingPolicy.HidePasswordReset {
|
||||
policy.HidePasswordReset = defaultPolicy.HidePasswordReset
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), policy.AllowUserNamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.HidePasswordReset, policy.PasswordlessType)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx,
|
||||
OrgAggregateFromWriteModel(&existingPolicy.WriteModel),
|
||||
policy.AllowUserNamePassword,
|
||||
policy.AllowRegister,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType,
|
||||
policy.PasswordCheckLifetime,
|
||||
policy.ExternalLoginCheckLifetime,
|
||||
policy.MFAInitSkipLifetime,
|
||||
policy.SecondFactorCheckLifetime,
|
||||
policy.MultiFactorCheckLifetime)
|
||||
if hasChanged {
|
||||
events = append(events, changedEvent)
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
"github.com/caos/zitadel/internal/static/mock"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
@ -16,9 +18,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/features"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
"github.com/caos/zitadel/internal/static/mock"
|
||||
)
|
||||
|
||||
func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
@ -165,6 +165,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -343,6 +348,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -547,6 +557,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -761,6 +776,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -990,6 +1010,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@ -1002,6 +1027,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*10,
|
||||
time.Hour*20,
|
||||
time.Hour*30,
|
||||
time.Hour*40,
|
||||
time.Hour*50,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1017,6 +1047,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1195,7 +1230,13 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
org.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.MultiFactorTypeU2FWithPIN),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", true, true, true, true, true, domain.PasswordlessTypeAllowed),
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1",
|
||||
true, true, true, true, true, domain.PasswordlessTypeAllowed,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
@ -1278,6 +1319,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1537,6 +1583,11 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -42,7 +42,12 @@ func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, pol
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType))
|
||||
policy.PasswordlessType,
|
||||
policy.PasswordCheckLifetime,
|
||||
policy.ExternalLoginCheckLifetime,
|
||||
policy.MFAInitSkipLifetime,
|
||||
policy.SecondFactorCheckLifetime,
|
||||
policy.MultiFactorCheckLifetime))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -100,7 +105,12 @@ func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string,
|
||||
policy.AllowExternalIDP,
|
||||
policy.ForceMFA,
|
||||
policy.HidePasswordReset,
|
||||
policy.PasswordlessType)
|
||||
policy.PasswordlessType,
|
||||
policy.PasswordCheckLifetime,
|
||||
policy.ExternalLoginCheckLifetime,
|
||||
policy.MFAInitSkipLifetime,
|
||||
policy.SecondFactorCheckLifetime,
|
||||
policy.MultiFactorCheckLifetime)
|
||||
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
@ -68,6 +69,11 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime time.Duration,
|
||||
) (*org.LoginPolicyChangedEvent, bool) {
|
||||
|
||||
changes := make([]policy.LoginPolicyChanges, 0)
|
||||
@ -86,6 +92,21 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
||||
if wm.HidePasswordReset != hidePasswordReset {
|
||||
changes = append(changes, policy.ChangeHidePasswordReset(hidePasswordReset))
|
||||
}
|
||||
if wm.PasswordCheckLifetime != passwordCheckLifetime {
|
||||
changes = append(changes, policy.ChangePasswordCheckLifetime(passwordCheckLifetime))
|
||||
}
|
||||
if wm.ExternalLoginCheckLifetime != externalLoginCheckLifetime {
|
||||
changes = append(changes, policy.ChangeExternalLoginCheckLifetime(externalLoginCheckLifetime))
|
||||
}
|
||||
if wm.MFAInitSkipLifetime != mfaInitSkipLifetime {
|
||||
changes = append(changes, policy.ChangeMFAInitSkipLifetime(mfaInitSkipLifetime))
|
||||
}
|
||||
if wm.SecondFactorCheckLifetime != secondFactorCheckLifetime {
|
||||
changes = append(changes, policy.ChangeSecondFactorCheckLifetime(secondFactorCheckLifetime))
|
||||
}
|
||||
if wm.MultiFactorCheckLifetime != multiFactorCheckLifetime {
|
||||
changes = append(changes, policy.ChangeMultiFactorCheckLifetime(multiFactorCheckLifetime))
|
||||
}
|
||||
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
|
||||
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@ -17,6 +18,14 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
var (
|
||||
duration10 = time.Hour * 10
|
||||
duration20 = time.Hour * 20
|
||||
duration30 = time.Hour * 30
|
||||
duration40 = time.Hour * 40
|
||||
duration50 = time.Hour * 50
|
||||
)
|
||||
|
||||
func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
@ -71,6 +80,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -80,11 +94,16 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -107,6 +126,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -117,11 +141,16 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -144,6 +173,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -158,6 +192,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
},
|
||||
@ -169,12 +208,17 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -183,12 +227,17 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||
AggregateID: "org1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -292,6 +341,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -305,6 +359,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -315,11 +374,16 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -341,6 +405,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -354,6 +423,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -364,12 +438,17 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDP: true,
|
||||
ForceMFA: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 1,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 3,
|
||||
SecondFactorCheckLifetime: time.Hour * 4,
|
||||
MultiFactorCheckLifetime: time.Hour * 5,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -391,6 +470,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -404,13 +488,31 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", false, false, false, false, false, domain.PasswordlessTypeNotAllowed),
|
||||
newLoginPolicyChangedEvent(context.Background(),
|
||||
"org1",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
&duration10,
|
||||
&duration20,
|
||||
&duration30,
|
||||
&duration40,
|
||||
&duration50,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
@ -421,11 +523,16 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.LoginPolicy{
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 10,
|
||||
ExternalLoginCheckLifetime: time.Hour * 20,
|
||||
MFAInitSkipLifetime: time.Hour * 30,
|
||||
SecondFactorCheckLifetime: time.Hour * 40,
|
||||
MultiFactorCheckLifetime: time.Hour * 50,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -434,12 +541,17 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
||||
AggregateID: "org1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
AllowRegister: false,
|
||||
AllowUsernamePassword: false,
|
||||
AllowExternalIDP: false,
|
||||
ForceMFA: false,
|
||||
HidePasswordReset: false,
|
||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
||||
PasswordCheckLifetime: time.Hour * 10,
|
||||
ExternalLoginCheckLifetime: time.Hour * 20,
|
||||
MFAInitSkipLifetime: time.Hour * 30,
|
||||
SecondFactorCheckLifetime: time.Hour * 40,
|
||||
MultiFactorCheckLifetime: time.Hour * 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -527,6 +639,11 @@ func TestCommandSide_RemoveLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -660,6 +777,11 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -694,6 +816,11 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -748,6 +875,11 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -905,6 +1037,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -939,6 +1076,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -985,6 +1127,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1038,6 +1185,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1099,6 +1251,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1710,17 +1867,35 @@ func TestCommandSide_RemoveMultiFactorLoginPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassword, register, externalIDP, mfa, passwordReset bool, passwordlessType domain.PasswordlessType) *org.LoginPolicyChangedEvent {
|
||||
func newLoginPolicyChangedEvent(ctx context.Context, orgID string, usernamePassword, register, externalIDP, mfa, passwordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordLifetime, externalLoginLifetime, mfaInitSkipLifetime, secondFactorLifetime, multiFactorLifetime *time.Duration) *org.LoginPolicyChangedEvent {
|
||||
changes := []policy.LoginPolicyChanges{
|
||||
policy.ChangeAllowUserNamePassword(usernamePassword),
|
||||
policy.ChangeAllowRegister(register),
|
||||
policy.ChangeAllowExternalIDP(externalIDP),
|
||||
policy.ChangeForceMFA(mfa),
|
||||
policy.ChangeHidePasswordReset(passwordReset),
|
||||
policy.ChangePasswordlessType(passwordlessType),
|
||||
}
|
||||
if passwordLifetime != nil {
|
||||
changes = append(changes, policy.ChangePasswordCheckLifetime(*passwordLifetime))
|
||||
}
|
||||
if externalLoginLifetime != nil {
|
||||
changes = append(changes, policy.ChangeExternalLoginCheckLifetime(*externalLoginLifetime))
|
||||
}
|
||||
if mfaInitSkipLifetime != nil {
|
||||
changes = append(changes, policy.ChangeMFAInitSkipLifetime(*mfaInitSkipLifetime))
|
||||
}
|
||||
if secondFactorLifetime != nil {
|
||||
changes = append(changes, policy.ChangeSecondFactorCheckLifetime(*secondFactorLifetime))
|
||||
}
|
||||
if multiFactorLifetime != nil {
|
||||
changes = append(changes, policy.ChangeMultiFactorCheckLifetime(*multiFactorLifetime))
|
||||
}
|
||||
event, _ := org.NewLoginPolicyChangedEvent(ctx,
|
||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
||||
[]policy.LoginPolicyChanges{
|
||||
policy.ChangeAllowUserNamePassword(usernamePassword),
|
||||
policy.ChangeAllowRegister(register),
|
||||
policy.ChangeAllowExternalIDP(externalIDP),
|
||||
policy.ChangeForceMFA(mfa),
|
||||
policy.ChangeHidePasswordReset(passwordReset),
|
||||
policy.ChangePasswordlessType(passwordlessType),
|
||||
},
|
||||
changes,
|
||||
)
|
||||
return event
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
@ -9,13 +11,18 @@ import (
|
||||
type LoginPolicyWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
AllowUserNamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
ForceMFA bool
|
||||
HidePasswordReset bool
|
||||
PasswordlessType domain.PasswordlessType
|
||||
State domain.PolicyState
|
||||
AllowUserNamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
ForceMFA bool
|
||||
HidePasswordReset bool
|
||||
PasswordlessType domain.PasswordlessType
|
||||
PasswordCheckLifetime time.Duration
|
||||
ExternalLoginCheckLifetime time.Duration
|
||||
MFAInitSkipLifetime time.Duration
|
||||
SecondFactorCheckLifetime time.Duration
|
||||
MultiFactorCheckLifetime time.Duration
|
||||
State domain.PolicyState
|
||||
}
|
||||
|
||||
func (wm *LoginPolicyWriteModel) Reduce() error {
|
||||
@ -28,6 +35,11 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
||||
wm.ForceMFA = e.ForceMFA
|
||||
wm.PasswordlessType = e.PasswordlessType
|
||||
wm.HidePasswordReset = e.HidePasswordReset
|
||||
wm.PasswordCheckLifetime = e.PasswordCheckLifetime
|
||||
wm.ExternalLoginCheckLifetime = e.ExternalLoginCheckLifetime
|
||||
wm.MFAInitSkipLifetime = e.MFAInitSkipLifetime
|
||||
wm.SecondFactorCheckLifetime = e.SecondFactorCheckLifetime
|
||||
wm.MultiFactorCheckLifetime = e.MultiFactorCheckLifetime
|
||||
wm.State = domain.PolicyStateActive
|
||||
case *policy.LoginPolicyChangedEvent:
|
||||
if e.AllowRegister != nil {
|
||||
@ -48,6 +60,21 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
||||
if e.PasswordlessType != nil {
|
||||
wm.PasswordlessType = *e.PasswordlessType
|
||||
}
|
||||
if e.PasswordCheckLifetime != nil {
|
||||
wm.PasswordCheckLifetime = *e.PasswordCheckLifetime
|
||||
}
|
||||
if e.ExternalLoginCheckLifetime != nil {
|
||||
wm.ExternalLoginCheckLifetime = *e.ExternalLoginCheckLifetime
|
||||
}
|
||||
if e.MFAInitSkipLifetime != nil {
|
||||
wm.MFAInitSkipLifetime = *e.MFAInitSkipLifetime
|
||||
}
|
||||
if e.SecondFactorCheckLifetime != nil {
|
||||
wm.SecondFactorCheckLifetime = *e.SecondFactorCheckLifetime
|
||||
}
|
||||
if e.MultiFactorCheckLifetime != nil {
|
||||
wm.MultiFactorCheckLifetime = *e.MultiFactorCheckLifetime
|
||||
}
|
||||
case *policy.LoginPolicyRemovedEvent:
|
||||
wm.State = domain.PolicyStateRemoved
|
||||
}
|
||||
|
@ -1157,6 +1157,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1187,6 +1192,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1218,6 +1228,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1265,6 +1280,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1346,6 +1366,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1434,6 +1459,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -1607,6 +1607,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1664,6 +1669,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1721,6 +1731,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1795,6 +1810,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1927,6 +1947,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2027,6 +2052,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2121,6 +2151,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2237,6 +2272,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
time.Hour*1,
|
||||
time.Hour*2,
|
||||
time.Hour*3,
|
||||
time.Hour*4,
|
||||
time.Hour*5,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -23,7 +23,6 @@ type SystemDefaults struct {
|
||||
SMTPPasswordVerificationKey *crypto.KeyConfig
|
||||
SMSVerificationKey *crypto.KeyConfig
|
||||
Multifactors MultifactorConfig
|
||||
VerificationLifetimes VerificationLifetimes
|
||||
DomainVerification DomainVerification
|
||||
Notifications Notifications
|
||||
KeyConfig KeyConfig
|
||||
@ -49,14 +48,6 @@ type OTPConfig struct {
|
||||
VerificationKey *crypto.KeyConfig
|
||||
}
|
||||
|
||||
type VerificationLifetimes struct {
|
||||
PasswordCheck time.Duration
|
||||
ExternalLoginCheck time.Duration
|
||||
MFAInitSkip time.Duration
|
||||
SecondFactorCheck time.Duration
|
||||
MultiFactorCheck time.Duration
|
||||
}
|
||||
|
||||
type DomainVerification struct {
|
||||
VerificationKey *crypto.KeyConfig
|
||||
VerificationGenerator crypto.GeneratorConfig
|
||||
|
@ -1,20 +1,29 @@
|
||||
package domain
|
||||
|
||||
import "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
type LoginPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Default bool
|
||||
AllowUsernamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
IDPProviders []*IDPProvider
|
||||
ForceMFA bool
|
||||
SecondFactors []SecondFactorType
|
||||
MultiFactors []MultiFactorType
|
||||
PasswordlessType PasswordlessType
|
||||
HidePasswordReset bool
|
||||
Default bool
|
||||
AllowUsernamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
IDPProviders []*IDPProvider
|
||||
ForceMFA bool
|
||||
SecondFactors []SecondFactorType
|
||||
MultiFactors []MultiFactorType
|
||||
PasswordlessType PasswordlessType
|
||||
HidePasswordReset bool
|
||||
PasswordCheckLifetime time.Duration
|
||||
ExternalLoginCheckLifetime time.Duration
|
||||
MFAInitSkipLifetime time.Duration
|
||||
SecondFactorCheckLifetime time.Duration
|
||||
MultiFactorCheckLifetime time.Duration
|
||||
}
|
||||
|
||||
type IDPProvider struct {
|
||||
|
@ -14,19 +14,24 @@ import (
|
||||
)
|
||||
|
||||
type LoginPolicy struct {
|
||||
OrgID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
AllowRegister bool
|
||||
AllowUsernamePassword bool
|
||||
AllowExternalIDPs bool
|
||||
ForceMFA bool
|
||||
SecondFactors []domain.SecondFactorType
|
||||
MultiFactors []domain.MultiFactorType
|
||||
PasswordlessType domain.PasswordlessType
|
||||
IsDefault bool
|
||||
HidePasswordReset bool
|
||||
OrgID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
AllowRegister bool
|
||||
AllowUsernamePassword bool
|
||||
AllowExternalIDPs bool
|
||||
ForceMFA bool
|
||||
SecondFactors []domain.SecondFactorType
|
||||
MultiFactors []domain.MultiFactorType
|
||||
PasswordlessType domain.PasswordlessType
|
||||
IsDefault bool
|
||||
HidePasswordReset bool
|
||||
PasswordCheckLifetime time.Duration
|
||||
ExternalLoginCheckLifetime time.Duration
|
||||
MFAInitSkipLifetime time.Duration
|
||||
SecondFactorCheckLifetime time.Duration
|
||||
MultiFactorCheckLifetime time.Duration
|
||||
}
|
||||
|
||||
type SecondFactors struct {
|
||||
@ -95,6 +100,26 @@ var (
|
||||
name: projection.LoginPolicyHidePWResetCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
LoginPolicyColumnPasswordCheckLifetime = Column{
|
||||
name: projection.PasswordCheckLifetimeCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
LoginPolicyColumnExternalLoginCheckLifetime = Column{
|
||||
name: projection.ExternalLoginCheckLifetimeCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
LoginPolicyColumnMFAInitSkipLifetime = Column{
|
||||
name: projection.MFAInitSkipLifetimeCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
LoginPolicyColumnSecondFactorCheckLifetime = Column{
|
||||
name: projection.SecondFactorCheckLifetimeCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
LoginPolicyColumnMultiFacotrCheckLifetime = Column{
|
||||
name: projection.MultiFactorCheckLifetimeCol,
|
||||
table: loginPolicyTable,
|
||||
}
|
||||
)
|
||||
|
||||
func (q *Queries) LoginPolicyByID(ctx context.Context, orgID string) (*LoginPolicy, error) {
|
||||
@ -234,6 +259,11 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy,
|
||||
LoginPolicyColumnPasswordlessType.identifier(),
|
||||
LoginPolicyColumnIsDefault.identifier(),
|
||||
LoginPolicyColumnHidePasswordReset.identifier(),
|
||||
LoginPolicyColumnPasswordCheckLifetime.identifier(),
|
||||
LoginPolicyColumnExternalLoginCheckLifetime.identifier(),
|
||||
LoginPolicyColumnMFAInitSkipLifetime.identifier(),
|
||||
LoginPolicyColumnSecondFactorCheckLifetime.identifier(),
|
||||
LoginPolicyColumnMultiFacotrCheckLifetime.identifier(),
|
||||
).From(loginPolicyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*LoginPolicy, error) {
|
||||
p := new(LoginPolicy)
|
||||
@ -253,6 +283,11 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy,
|
||||
&p.PasswordlessType,
|
||||
&p.IsDefault,
|
||||
&p.HidePasswordReset,
|
||||
&p.PasswordCheckLifetime,
|
||||
&p.ExternalLoginCheckLifetime,
|
||||
&p.MFAInitSkipLifetime,
|
||||
&p.SecondFactorCheckLifetime,
|
||||
&p.MultiFactorCheckLifetime,
|
||||
)
|
||||
if err != nil {
|
||||
if errs.Is(err, sql.ErrNoRows) {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
errs "github.com/caos/zitadel/internal/errors"
|
||||
@ -41,7 +42,12 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` zitadel.projections.login_policies.multi_factors,`+
|
||||
` zitadel.projections.login_policies.passwordless_type,`+
|
||||
` zitadel.projections.login_policies.is_default,`+
|
||||
` zitadel.projections.login_policies.hide_password_reset`+
|
||||
` zitadel.projections.login_policies.hide_password_reset,`+
|
||||
` zitadel.projections.login_policies.password_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.external_login_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` zitadel.projections.login_policies.second_factor_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM zitadel.projections.login_policies`),
|
||||
nil,
|
||||
nil,
|
||||
@ -72,7 +78,12 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` zitadel.projections.login_policies.multi_factors,`+
|
||||
` zitadel.projections.login_policies.passwordless_type,`+
|
||||
` zitadel.projections.login_policies.is_default,`+
|
||||
` zitadel.projections.login_policies.hide_password_reset`+
|
||||
` zitadel.projections.login_policies.hide_password_reset,`+
|
||||
` zitadel.projections.login_policies.password_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.external_login_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` zitadel.projections.login_policies.second_factor_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM zitadel.projections.login_policies`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
@ -88,6 +99,11 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
"passwordless_type",
|
||||
"is_default",
|
||||
"hide_password_reset",
|
||||
"password_check_lifetime",
|
||||
"external_login_check_lifetime",
|
||||
"mfa_init_skip_lifetime",
|
||||
"second_factor_check_lifetime",
|
||||
"multi_factor_check_lifetime",
|
||||
},
|
||||
[]driver.Value{
|
||||
"ro",
|
||||
@ -103,23 +119,33 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
domain.PasswordlessTypeAllowed,
|
||||
true,
|
||||
true,
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &LoginPolicy{
|
||||
OrgID: "ro",
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDPs: true,
|
||||
ForceMFA: true,
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
IsDefault: true,
|
||||
HidePasswordReset: true,
|
||||
OrgID: "ro",
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
AllowRegister: true,
|
||||
AllowUsernamePassword: true,
|
||||
AllowExternalIDPs: true,
|
||||
ForceMFA: true,
|
||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
IsDefault: true,
|
||||
HidePasswordReset: true,
|
||||
PasswordCheckLifetime: time.Hour * 2,
|
||||
ExternalLoginCheckLifetime: time.Hour * 2,
|
||||
MFAInitSkipLifetime: time.Hour * 2,
|
||||
SecondFactorCheckLifetime: time.Hour * 2,
|
||||
MultiFactorCheckLifetime: time.Hour * 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -139,7 +165,12 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` zitadel.projections.login_policies.multi_factors,`+
|
||||
` zitadel.projections.login_policies.passwordless_type,`+
|
||||
` zitadel.projections.login_policies.is_default,`+
|
||||
` zitadel.projections.login_policies.hide_password_reset`+
|
||||
` zitadel.projections.login_policies.hide_password_reset,`+
|
||||
` zitadel.projections.login_policies.password_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.external_login_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` zitadel.projections.login_policies.second_factor_check_lifetime,`+
|
||||
` zitadel.projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM zitadel.projections.login_policies`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
|
@ -111,6 +111,11 @@ const (
|
||||
LoginPolicyPasswordlessTypeCol = "passwordless_type"
|
||||
LoginPolicyIsDefaultCol = "is_default"
|
||||
LoginPolicyHidePWResetCol = "hide_password_reset"
|
||||
PasswordCheckLifetimeCol = "password_check_lifetime"
|
||||
ExternalLoginCheckLifetimeCol = "external_login_check_lifetime"
|
||||
MFAInitSkipLifetimeCol = "mfa_init_skip_lifetime"
|
||||
SecondFactorCheckLifetimeCol = "second_factor_check_lifetime"
|
||||
MultiFactorCheckLifetimeCol = "multi_factor_check_lifetime"
|
||||
)
|
||||
|
||||
func (p *LoginPolicyProjection) reduceLoginPolicyAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
@ -140,6 +145,11 @@ func (p *LoginPolicyProjection) reduceLoginPolicyAdded(event eventstore.Event) (
|
||||
handler.NewCol(LoginPolicyPasswordlessTypeCol, policyEvent.PasswordlessType),
|
||||
handler.NewCol(LoginPolicyIsDefaultCol, isDefault),
|
||||
handler.NewCol(LoginPolicyHidePWResetCol, policyEvent.HidePasswordReset),
|
||||
handler.NewCol(PasswordCheckLifetimeCol, policyEvent.PasswordCheckLifetime),
|
||||
handler.NewCol(ExternalLoginCheckLifetimeCol, policyEvent.ExternalLoginCheckLifetime),
|
||||
handler.NewCol(MFAInitSkipLifetimeCol, policyEvent.MFAInitSkipLifetime),
|
||||
handler.NewCol(SecondFactorCheckLifetimeCol, policyEvent.SecondFactorCheckLifetime),
|
||||
handler.NewCol(MultiFactorCheckLifetimeCol, policyEvent.MultiFactorCheckLifetime),
|
||||
}), nil
|
||||
}
|
||||
|
||||
@ -177,6 +187,22 @@ func (p *LoginPolicyProjection) reduceLoginPolicyChanged(event eventstore.Event)
|
||||
if policyEvent.HidePasswordReset != nil {
|
||||
cols = append(cols, handler.NewCol(LoginPolicyHidePWResetCol, *policyEvent.HidePasswordReset))
|
||||
}
|
||||
if policyEvent.PasswordCheckLifetime != nil {
|
||||
cols = append(cols, handler.NewCol(PasswordCheckLifetimeCol, *policyEvent.PasswordCheckLifetime))
|
||||
}
|
||||
if policyEvent.ExternalLoginCheckLifetime != nil {
|
||||
cols = append(cols, handler.NewCol(ExternalLoginCheckLifetimeCol, *policyEvent.ExternalLoginCheckLifetime))
|
||||
}
|
||||
if policyEvent.MFAInitSkipLifetime != nil {
|
||||
cols = append(cols, handler.NewCol(MFAInitSkipLifetimeCol, *policyEvent.MFAInitSkipLifetime))
|
||||
}
|
||||
if policyEvent.SecondFactorCheckLifetime != nil {
|
||||
cols = append(cols, handler.NewCol(SecondFactorCheckLifetimeCol, *policyEvent.SecondFactorCheckLifetime))
|
||||
}
|
||||
if policyEvent.MultiFactorCheckLifetime != nil {
|
||||
cols = append(cols, handler.NewCol(MultiFactorCheckLifetimeCol, *policyEvent.MultiFactorCheckLifetime))
|
||||
}
|
||||
|
||||
return crdb.NewUpdateStatement(
|
||||
&policyEvent,
|
||||
cols,
|
||||
|
@ -2,6 +2,7 @@ package projection
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
@ -29,13 +30,18 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
repository.EventType(org.LoginPolicyAddedEventType),
|
||||
org.AggregateType,
|
||||
[]byte(`{
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": false,
|
||||
"forceMFA": false,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1
|
||||
}`),
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": false,
|
||||
"forceMFA": false,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1,
|
||||
"passwordCheckLifetime": 10000000,
|
||||
"externalLoginCheckLifetime": 10000000,
|
||||
"mfaInitSkipLifetime": 10000000,
|
||||
"secondFactorCheckLifetime": 10000000,
|
||||
"multiFactorCheckLifetime": 10000000
|
||||
}`),
|
||||
), org.LoginPolicyAddedEventMapper),
|
||||
},
|
||||
reduce: (&LoginPolicyProjection{}).reduceLoginPolicyAdded,
|
||||
@ -47,7 +53,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO zitadel.projections.login_policies (aggregate_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||
expectedStmt: "INSERT INTO zitadel.projections.login_policies (aggregate_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -60,6 +66,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
domain.PasswordlessTypeAllowed,
|
||||
false,
|
||||
true,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -74,13 +85,18 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
repository.EventType(org.LoginPolicyChangedEventType),
|
||||
org.AggregateType,
|
||||
[]byte(`{
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": true,
|
||||
"forceMFA": true,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1
|
||||
}`),
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": true,
|
||||
"forceMFA": true,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1,
|
||||
"passwordCheckLifetime": 10000000,
|
||||
"externalLoginCheckLifetime": 10000000,
|
||||
"mfaInitSkipLifetime": 10000000,
|
||||
"secondFactorCheckLifetime": 10000000,
|
||||
"multiFactorCheckLifetime": 10000000
|
||||
}`),
|
||||
), org.LoginPolicyChangedEventMapper),
|
||||
},
|
||||
want: wantReduce{
|
||||
@ -91,7 +107,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE zitadel.projections.login_policies SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (aggregate_id = $9)",
|
||||
expectedStmt: "UPDATE zitadel.projections.login_policies SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (aggregate_id = $14)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@ -101,6 +117,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
true,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
"agg-id",
|
||||
},
|
||||
},
|
||||
@ -271,12 +292,17 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
repository.EventType(iam.LoginPolicyAddedEventType),
|
||||
iam.AggregateType,
|
||||
[]byte(`{
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": false,
|
||||
"forceMFA": false,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1
|
||||
"allowUsernamePassword": true,
|
||||
"allowRegister": true,
|
||||
"allowExternalIdp": false,
|
||||
"forceMFA": false,
|
||||
"hidePasswordReset": true,
|
||||
"passwordlessType": 1,
|
||||
"passwordCheckLifetime": 10000000,
|
||||
"externalLoginCheckLifetime": 10000000,
|
||||
"mfaInitSkipLifetime": 10000000,
|
||||
"secondFactorCheckLifetime": 10000000,
|
||||
"multiFactorCheckLifetime": 10000000
|
||||
}`),
|
||||
), iam.LoginPolicyAddedEventMapper),
|
||||
},
|
||||
@ -288,7 +314,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO zitadel.projections.login_policies (aggregate_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||
expectedStmt: "INSERT INTO zitadel.projections.login_policies (aggregate_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -301,6 +327,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
||||
domain.PasswordlessTypeAllowed,
|
||||
true,
|
||||
true,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
time.Millisecond * 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2,6 +2,7 @@ package iam
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
@ -28,6 +29,11 @@ func NewLoginPolicyAddedEvent(
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime time.Duration,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
||||
@ -40,7 +46,12 @@ func NewLoginPolicyAddedEvent(
|
||||
allowExternalIDP,
|
||||
forceMFA,
|
||||
hidePasswordReset,
|
||||
passwordlessType),
|
||||
passwordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
@ -29,6 +30,11 @@ func NewLoginPolicyAddedEvent(
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime time.Duration,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
||||
@ -41,7 +47,12 @@ func NewLoginPolicyAddedEvent(
|
||||
allowExternalIDP,
|
||||
forceMFA,
|
||||
hidePasswordReset,
|
||||
passwordlessType),
|
||||
passwordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
@ -19,12 +20,17 @@ const (
|
||||
type LoginPolicyAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AllowUserNamePassword bool `json:"allowUsernamePassword,omitempty"`
|
||||
AllowRegister bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
AllowUserNamePassword bool `json:"allowUsernamePassword,omitempty"`
|
||||
AllowRegister bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
PasswordCheckLifetime time.Duration `json:"passwordCheckLifetime,omitempty"`
|
||||
ExternalLoginCheckLifetime time.Duration `json:"externalLoginCheckLifetime,omitempty"`
|
||||
MFAInitSkipLifetime time.Duration `json:"mfaInitSkipLifetime,omitempty"`
|
||||
SecondFactorCheckLifetime time.Duration `json:"secondFactorCheckLifetime,omitempty"`
|
||||
MultiFactorCheckLifetime time.Duration `json:"multiFactorCheckLifetime,omitempty"`
|
||||
}
|
||||
|
||||
func (e *LoginPolicyAddedEvent) Data() interface{} {
|
||||
@ -43,15 +49,25 @@ func NewLoginPolicyAddedEvent(
|
||||
forceMFA,
|
||||
hidePasswordReset bool,
|
||||
passwordlessType domain.PasswordlessType,
|
||||
passwordCheckLifetime,
|
||||
externalLoginCheckLifetime,
|
||||
mfaInitSkipLifetime,
|
||||
secondFactorCheckLifetime,
|
||||
multiFactorCheckLifetime time.Duration,
|
||||
) *LoginPolicyAddedEvent {
|
||||
return &LoginPolicyAddedEvent{
|
||||
BaseEvent: *base,
|
||||
AllowExternalIDP: allowExternalIDP,
|
||||
AllowRegister: allowRegister,
|
||||
AllowUserNamePassword: allowUserNamePassword,
|
||||
ForceMFA: forceMFA,
|
||||
PasswordlessType: passwordlessType,
|
||||
HidePasswordReset: hidePasswordReset,
|
||||
BaseEvent: *base,
|
||||
AllowExternalIDP: allowExternalIDP,
|
||||
AllowRegister: allowRegister,
|
||||
AllowUserNamePassword: allowUserNamePassword,
|
||||
ForceMFA: forceMFA,
|
||||
PasswordlessType: passwordlessType,
|
||||
HidePasswordReset: hidePasswordReset,
|
||||
PasswordCheckLifetime: passwordCheckLifetime,
|
||||
ExternalLoginCheckLifetime: externalLoginCheckLifetime,
|
||||
MFAInitSkipLifetime: mfaInitSkipLifetime,
|
||||
SecondFactorCheckLifetime: secondFactorCheckLifetime,
|
||||
MultiFactorCheckLifetime: multiFactorCheckLifetime,
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,12 +87,17 @@ func LoginPolicyAddedEventMapper(event *repository.Event) (eventstore.Event, err
|
||||
type LoginPolicyChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AllowUserNamePassword *bool `json:"allowUsernamePassword,omitempty"`
|
||||
AllowRegister *bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA *bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType *domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
AllowUserNamePassword *bool `json:"allowUsernamePassword,omitempty"`
|
||||
AllowRegister *bool `json:"allowRegister,omitempty"`
|
||||
AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"`
|
||||
ForceMFA *bool `json:"forceMFA,omitempty"`
|
||||
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
||||
PasswordlessType *domain.PasswordlessType `json:"passwordlessType,omitempty"`
|
||||
PasswordCheckLifetime *time.Duration `json:"passwordCheckLifetime,omitempty"`
|
||||
ExternalLoginCheckLifetime *time.Duration `json:"externalLoginCheckLifetime,omitempty"`
|
||||
MFAInitSkipLifetime *time.Duration `json:"mfaInitSkipLifetime,omitempty"`
|
||||
SecondFactorCheckLifetime *time.Duration `json:"secondFactorCheckLifetime,omitempty"`
|
||||
MultiFactorCheckLifetime *time.Duration `json:"multiFactorCheckLifetime,omitempty"`
|
||||
}
|
||||
|
||||
func (e *LoginPolicyChangedEvent) Data() interface{} {
|
||||
@ -141,6 +162,31 @@ func ChangeHidePasswordReset(hidePasswordReset bool) func(*LoginPolicyChangedEve
|
||||
}
|
||||
}
|
||||
|
||||
func ChangePasswordCheckLifetime(passwordCheckLifetime time.Duration) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.PasswordCheckLifetime = &passwordCheckLifetime
|
||||
}
|
||||
}
|
||||
func ChangeExternalLoginCheckLifetime(externalLoginCheckLifetime time.Duration) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.ExternalLoginCheckLifetime = &externalLoginCheckLifetime
|
||||
}
|
||||
}
|
||||
func ChangeMFAInitSkipLifetime(mfaInitSkipLifetime time.Duration) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.MFAInitSkipLifetime = &mfaInitSkipLifetime
|
||||
}
|
||||
}
|
||||
func ChangeSecondFactorCheckLifetime(secondFactorCheckLifetime time.Duration) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.SecondFactorCheckLifetime = &secondFactorCheckLifetime
|
||||
}
|
||||
}
|
||||
func ChangeMultiFactorCheckLifetime(multiFactorCheckLifetime time.Duration) func(*LoginPolicyChangedEvent) {
|
||||
return func(e *LoginPolicyChangedEvent) {
|
||||
e.MultiFactorCheckLifetime = &multiFactorCheckLifetime
|
||||
}
|
||||
}
|
||||
func LoginPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &LoginPolicyChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
|
@ -3459,6 +3459,11 @@ message UpdateLoginPolicyRequest {
|
||||
description: "defines if password reset link should be shown in the login screen"
|
||||
}
|
||||
];
|
||||
google.protobuf.Duration password_check_lifetime = 7;
|
||||
google.protobuf.Duration external_login_check_lifetime = 8;
|
||||
google.protobuf.Duration mfa_init_skip_lifetime = 9;
|
||||
google.protobuf.Duration second_factor_check_lifetime = 10;
|
||||
google.protobuf.Duration multi_factor_check_lifetime = 11;
|
||||
}
|
||||
|
||||
message UpdateLoginPolicyResponse {
|
||||
|
@ -4397,6 +4397,11 @@ message AddCustomLoginPolicyRequest {
|
||||
bool force_mfa = 4;
|
||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||
bool hide_password_reset = 6;
|
||||
google.protobuf.Duration password_check_lifetime = 7;
|
||||
google.protobuf.Duration external_login_check_lifetime = 8;
|
||||
google.protobuf.Duration mfa_init_skip_lifetime = 9;
|
||||
google.protobuf.Duration second_factor_check_lifetime = 10;
|
||||
google.protobuf.Duration multi_factor_check_lifetime = 11;
|
||||
}
|
||||
|
||||
message AddCustomLoginPolicyResponse {
|
||||
@ -4410,6 +4415,11 @@ message UpdateCustomLoginPolicyRequest {
|
||||
bool force_mfa = 4;
|
||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||
bool hide_password_reset = 6;
|
||||
google.protobuf.Duration password_check_lifetime = 7;
|
||||
google.protobuf.Duration external_login_check_lifetime = 8;
|
||||
google.protobuf.Duration mfa_init_skip_lifetime = 9;
|
||||
google.protobuf.Duration second_factor_check_lifetime = 10;
|
||||
google.protobuf.Duration multi_factor_check_lifetime = 11;
|
||||
}
|
||||
|
||||
message UpdateCustomLoginPolicyResponse {
|
||||
|
@ -1,6 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "zitadel/object.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
|
||||
package zitadel.policy.v1;
|
||||
@ -128,6 +129,12 @@ message LoginPolicy {
|
||||
description: "defines if password reset link should be shown in the login screen"
|
||||
}
|
||||
];
|
||||
google.protobuf.Duration password_check_lifetime = 9;
|
||||
google.protobuf.Duration external_login_check_lifetime = 10;
|
||||
google.protobuf.Duration mfa_init_skip_lifetime = 11;
|
||||
google.protobuf.Duration second_factor_check_lifetime = 12;
|
||||
google.protobuf.Duration multi_factor_check_lifetime = 13;
|
||||
|
||||
}
|
||||
|
||||
enum SecondFactorType {
|
||||
|
Loading…
x
Reference in New Issue
Block a user