mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-30 06:30:55 +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 /> |
|
| sid | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
| token | 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 | - | |
|
| force_mfa | bool | - | |
|
||||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||||
| hide_password_reset | 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 | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -3710,7 +3715,7 @@ This is an empty request
|
|||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
| sid | 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 | - | |
|
| force_mfa | bool | - | |
|
||||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||||
| hide_password_reset | 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 | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -7751,6 +7756,11 @@ This is an empty request
|
|||||||
| force_mfa | bool | - | |
|
| force_mfa | bool | - | |
|
||||||
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
| passwordless_type | zitadel.policy.v1.PasswordlessType | - | enum.defined_only: true<br /> |
|
||||||
| hide_password_reset | 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 | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,6 +63,11 @@ title: zitadel/policy.proto
|
|||||||
| passwordless_type | PasswordlessType | - | |
|
| passwordless_type | PasswordlessType | - | |
|
||||||
| is_default | bool | - | |
|
| is_default | bool | - | |
|
||||||
| hide_password_reset | 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 | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,11 @@ func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.Log
|
|||||||
ForceMFA: p.ForceMfa,
|
ForceMFA: p.ForceMfa,
|
||||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||||
HidePasswordReset: p.HidePasswordReset,
|
HidePasswordReset: p.HidePasswordReset,
|
||||||
|
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||||
|
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||||
|
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||||
|
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||||
|
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,11 @@ func addLoginPolicyToDomain(p *mgmt_pb.AddCustomLoginPolicyRequest) *domain.Logi
|
|||||||
ForceMFA: p.ForceMfa,
|
ForceMFA: p.ForceMfa,
|
||||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||||
HidePasswordReset: p.HidePasswordReset,
|
HidePasswordReset: p.HidePasswordReset,
|
||||||
|
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||||
|
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||||
|
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||||
|
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||||
|
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +32,11 @@ func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domai
|
|||||||
ForceMFA: p.ForceMfa,
|
ForceMFA: p.ForceMfa,
|
||||||
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType),
|
||||||
HidePasswordReset: p.HidePasswordReset,
|
HidePasswordReset: p.HidePasswordReset,
|
||||||
|
PasswordCheckLifetime: p.PasswordCheckLifetime.AsDuration(),
|
||||||
|
ExternalLoginCheckLifetime: p.ExternalLoginCheckLifetime.AsDuration(),
|
||||||
|
MFAInitSkipLifetime: p.MfaInitSkipLifetime.AsDuration(),
|
||||||
|
SecondFactorCheckLifetime: p.SecondFactorCheckLifetime.AsDuration(),
|
||||||
|
MultiFactorCheckLifetime: p.MultiFactorCheckLifetime.AsDuration(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/query"
|
"github.com/caos/zitadel/internal/query"
|
||||||
"github.com/caos/zitadel/pkg/grpc/object"
|
"github.com/caos/zitadel/pkg/grpc/object"
|
||||||
policy_pb "github.com/caos/zitadel/pkg/grpc/policy"
|
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"
|
timestamp_pb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,6 +18,11 @@ func ModelLoginPolicyToPb(policy *query.LoginPolicy) *policy_pb.LoginPolicy {
|
|||||||
ForceMfa: policy.ForceMFA,
|
ForceMfa: policy.ForceMFA,
|
||||||
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
|
PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType),
|
||||||
HidePasswordReset: policy.HidePasswordReset,
|
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{
|
Details: &object.ObjectDetails{
|
||||||
Sequence: policy.Sequence,
|
Sequence: policy.Sequence,
|
||||||
CreationDate: timestamp_pb.New(policy.CreationDate),
|
CreationDate: timestamp_pb.New(policy.CreationDate),
|
||||||
|
@ -50,12 +50,6 @@ type AuthRequestRepo struct {
|
|||||||
ApplicationProvider applicationProvider
|
ApplicationProvider applicationProvider
|
||||||
|
|
||||||
IdGenerator id.Generator
|
IdGenerator id.Generator
|
||||||
|
|
||||||
PasswordCheckLifeTime time.Duration
|
|
||||||
ExternalLoginCheckLifeTime time.Duration
|
|
||||||
MFAInitSkippedLifeTime time.Duration
|
|
||||||
SecondFactorCheckLifeTime time.Duration
|
|
||||||
MultiFactorCheckLifeTime time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type labelPolicyProvider interface {
|
type labelPolicyProvider interface {
|
||||||
@ -761,7 +755,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
|
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
|
selectedIDPConfigID := request.SelectedIDPConfigID
|
||||||
if selectedIDPConfigID == "" {
|
if selectedIDPConfigID == "" {
|
||||||
selectedIDPConfigID = userSession.SelectedIDPConfigID
|
selectedIDPConfigID = userSession.SelectedIDPConfigID
|
||||||
@ -858,7 +852,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use
|
|||||||
|
|
||||||
var step domain.NextStep
|
var step domain.NextStep
|
||||||
if request.LoginPolicy.PasswordlessType != domain.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() {
|
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
|
request.AuthTime = userSession.PasswordlessVerification
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -875,7 +869,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use
|
|||||||
return &domain.InitPasswordStep{}
|
return &domain.InitPasswordStep{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkVerificationTimeMaxAge(userSession.PasswordVerification, repo.PasswordCheckLifeTime, request) {
|
if checkVerificationTimeMaxAge(userSession.PasswordVerification, request.LoginPolicy.PasswordCheckLifetime, request) {
|
||||||
request.PasswordVerified = true
|
request.PasswordVerified = true
|
||||||
request.AuthTime = userSession.PasswordVerification
|
request.AuthTime = userSession.PasswordVerification
|
||||||
return nil
|
return nil
|
||||||
@ -890,7 +884,7 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
|
|||||||
mfaLevel := request.MFALevel()
|
mfaLevel := request.MFALevel()
|
||||||
allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy)
|
allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy)
|
||||||
promptRequired := (model.MFALevelToDomain(user.MFAMaxSetUp) < mfaLevel) || (len(allowedProviders) == 0 && required)
|
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)
|
types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy)
|
||||||
if promptRequired && len(types) == 0 {
|
if promptRequired && len(types) == 0 {
|
||||||
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
|
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
|
fallthrough
|
||||||
case domain.MFALevelSecondFactor:
|
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.MFAsVerified = append(request.MFAsVerified, model.MFATypeToDomain(userSession.SecondFactorVerificationType))
|
||||||
request.AuthTime = userSession.SecondFactorVerification
|
request.AuthTime = userSession.SecondFactorVerification
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case domain.MFALevelMultiFactor:
|
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.MFAsVerified = append(request.MFAsVerified, model.MFATypeToDomain(userSession.MultiFactorVerificationType))
|
||||||
request.AuthTime = userSession.MultiFactorVerification
|
request.AuthTime = userSession.MultiFactorVerification
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
@ -930,11 +924,11 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
|
|||||||
}, false, nil
|
}, 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 {
|
if user.MFAMaxSetUp > model.MFALevelNotSetUp {
|
||||||
return true
|
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) {
|
func (repo *AuthRequestRepo) getPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) {
|
||||||
|
@ -263,11 +263,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
applicationProvider applicationProvider
|
applicationProvider applicationProvider
|
||||||
loginPolicyProvider loginPolicyViewProvider
|
loginPolicyProvider loginPolicyViewProvider
|
||||||
lockoutPolicyProvider lockoutPolicyViewProvider
|
lockoutPolicyProvider lockoutPolicyViewProvider
|
||||||
PasswordCheckLifeTime time.Duration
|
|
||||||
ExternalLoginCheckLifeTime time.Duration
|
|
||||||
MFAInitSkippedLifeTime time.Duration
|
|
||||||
SecondFactorCheckLifeTime time.Duration
|
|
||||||
MultiFactorCheckLifeTime time.Duration
|
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
request *domain.AuthRequest
|
request *domain.AuthRequest
|
||||||
@ -572,12 +567,16 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
|
||||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||||
policy: &query.LockoutPolicy{
|
policy: &query.LockoutPolicy{
|
||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
loginPolicyProvider: &mockLoginPolicy{
|
||||||
|
policy: &query.LoginPolicy{
|
||||||
|
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||||
[]domain.NextStep{&domain.PasswordlessRegistrationPromptStep{}},
|
[]domain.NextStep{&domain.PasswordlessRegistrationPromptStep{}},
|
||||||
@ -597,7 +596,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
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},
|
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||||
[]domain.NextStep{&domain.PasswordlessStep{}},
|
[]domain.NextStep{&domain.PasswordlessStep{}},
|
||||||
@ -618,7 +621,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
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},
|
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{PasswordlessType: domain.PasswordlessTypeAllowed}}, false},
|
||||||
[]domain.NextStep{&domain.PasswordlessStep{PasswordSet: true}},
|
[]domain.NextStep{&domain.PasswordlessStep{PasswordSet: true}},
|
||||||
@ -645,13 +652,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
MultiFactorCheckLifeTime: 10 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||||
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
|
||||||
|
MultiFactorCheckLifetime: 10 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
||||||
@ -693,9 +700,18 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
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"}},
|
[]domain.NextStep{&domain.ExternalLoginStep{SelectedIDPConfigID: "IDPConfigID"}},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -715,23 +731,21 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
userGrantProvider: &mockUserGrants{},
|
userGrantProvider: &mockUserGrants{},
|
||||||
projectProvider: &mockProject{},
|
projectProvider: &mockProject{},
|
||||||
applicationProvider: &mockApp{app: &query.App{OIDCConfig: &query.OIDCApp{AppType: domain.OIDCApplicationTypeWeb}}},
|
applicationProvider: &mockApp{app: &query.App{OIDCConfig: &query.OIDCApp{AppType: domain.OIDCApplicationTypeWeb}}},
|
||||||
loginPolicyProvider: &mockLoginPolicy{
|
|
||||||
policy: &query.LoginPolicy{},
|
|
||||||
},
|
|
||||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||||
policy: &query.LockoutPolicy{
|
policy: &query.LockoutPolicy{
|
||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
SelectedIDPConfigID: "IDPConfigID",
|
SelectedIDPConfigID: "IDPConfigID",
|
||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{},
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
ExternalLoginCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
@ -751,7 +765,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
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},
|
args{&domain.AuthRequest{UserID: "UserID", LoginPolicy: &domain.LoginPolicy{}}, false},
|
||||||
[]domain.NextStep{&domain.PasswordStep{}},
|
[]domain.NextStep{&domain.PasswordStep{}},
|
||||||
@ -779,15 +797,16 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
SelectedIDPConfigID: "IDPConfigID",
|
SelectedIDPConfigID: "IDPConfigID",
|
||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{},
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
ExternalLoginCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
nil,
|
nil,
|
||||||
@ -811,14 +830,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||||
@ -844,14 +863,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||||
@ -878,9 +897,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
@ -888,6 +904,9 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
SelectedIDPConfigID: "IDPConfigID",
|
SelectedIDPConfigID: "IDPConfigID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
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},
|
}, false},
|
||||||
[]domain.NextStep{&domain.MFAVerificationStep{
|
[]domain.NextStep{&domain.MFAVerificationStep{
|
||||||
@ -915,14 +934,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.ChangePasswordStep{}},
|
[]domain.NextStep{&domain.ChangePasswordStep{}},
|
||||||
@ -946,13 +965,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
[]domain.NextStep{&domain.VerifyEMailStep{}},
|
||||||
@ -977,13 +996,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.ChangePasswordStep{}, &domain.VerifyEMailStep{}},
|
[]domain.NextStep{&domain.ChangePasswordStep{}, &domain.VerifyEMailStep{}},
|
||||||
@ -1011,14 +1030,14 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
@ -1046,8 +1065,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1055,6 +1072,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
@ -1082,8 +1101,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1091,6 +1108,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.LoginSucceededStep{}, &domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.LoginSucceededStep{}, &domain.RedirectToCallbackStep{}},
|
||||||
@ -1120,8 +1139,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1129,6 +1146,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.GrantRequiredStep{}},
|
[]domain.NextStep{&domain.GrantRequiredStep{}},
|
||||||
@ -1159,8 +1178,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1168,6 +1185,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
@ -1197,8 +1216,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1206,6 +1223,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.ProjectRequiredStep{}},
|
[]domain.NextStep{&domain.ProjectRequiredStep{}},
|
||||||
@ -1236,8 +1255,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{&domain.AuthRequest{
|
args{&domain.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
@ -1245,6 +1262,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
Request: &domain.AuthRequestOIDC{},
|
Request: &domain.AuthRequestOIDC{},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
[]domain.NextStep{&domain.RedirectToCallbackStep{}},
|
||||||
@ -1266,9 +1285,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
loginPolicyProvider: &mockLoginPolicy{
|
||||||
|
policy: &query.LoginPolicy{
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
userEventProvider: &mockEventUser{},
|
userEventProvider: &mockEventUser{},
|
||||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
@ -1299,8 +1322,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ShowFailures: true,
|
ShowFailures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
|
||||||
},
|
},
|
||||||
args{
|
args{
|
||||||
&domain.AuthRequest{
|
&domain.AuthRequest{
|
||||||
@ -1309,6 +1330,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
LinkingUsers: []*domain.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
|
LinkingUsers: []*domain.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
|
PasswordCheckLifetime: 10 * 24 * time.Hour,
|
||||||
},
|
},
|
||||||
}, false},
|
}, false},
|
||||||
[]domain.NextStep{&domain.LinkUsersStep{}},
|
[]domain.NextStep{&domain.LinkUsersStep{}},
|
||||||
@ -1329,11 +1352,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
ApplicationProvider: tt.fields.applicationProvider,
|
ApplicationProvider: tt.fields.applicationProvider,
|
||||||
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
|
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
|
||||||
LockoutPolicyViewProvider: tt.fields.lockoutPolicyProvider,
|
LockoutPolicyViewProvider: tt.fields.lockoutPolicyProvider,
|
||||||
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
|
|
||||||
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
|
|
||||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
|
||||||
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
|
|
||||||
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
|
|
||||||
}
|
}
|
||||||
got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn)
|
got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn)
|
||||||
if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) {
|
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) {
|
func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
||||||
type fields struct {
|
|
||||||
MFAInitSkippedLifeTime time.Duration
|
|
||||||
SecondFactorCheckLifeTime time.Duration
|
|
||||||
MultiFactorCheckLifeTime time.Duration
|
|
||||||
}
|
|
||||||
type args struct {
|
type args struct {
|
||||||
userSession *user_model.UserSessionView
|
userSession *user_model.UserSessionView
|
||||||
request *domain.AuthRequest
|
request *domain.AuthRequest
|
||||||
@ -1358,7 +1371,6 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fields fields
|
|
||||||
args args
|
args args
|
||||||
want domain.NextStep
|
want domain.NextStep
|
||||||
wantChecked bool
|
wantChecked bool
|
||||||
@ -1377,13 +1389,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
//},
|
//},
|
||||||
{
|
{
|
||||||
"not set up, forced by policy, no mfas configured, error",
|
"not set up, forced by policy, no mfas configured, error",
|
||||||
fields{
|
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
@ -1398,12 +1408,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not set up, no mfas configured, no prompt and true",
|
"not set up, no mfas configured, no prompt and true",
|
||||||
fields{
|
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{},
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
HumanView: &user_model.HumanView{
|
HumanView: &user_model.HumanView{
|
||||||
@ -1417,13 +1426,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not set up, prompt and false",
|
"not set up, prompt and false",
|
||||||
fields{
|
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
@ -1442,14 +1449,12 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not set up, forced by org, true",
|
"not set up, forced by org, true",
|
||||||
fields{
|
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
@ -1469,12 +1474,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not set up and skipped, true",
|
"not set up and skipped, true",
|
||||||
fields{
|
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{},
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
HumanView: &user_model.HumanView{
|
HumanView: &user_model.HumanView{
|
||||||
@ -1489,13 +1493,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checked second factor, true",
|
"checked second factor, true",
|
||||||
fields{
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
@ -1512,13 +1514,11 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"not checked, check and false",
|
"not checked, check and false",
|
||||||
fields{
|
|
||||||
SecondFactorCheckLifeTime: 18 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
request: &domain.AuthRequest{
|
request: &domain.AuthRequest{
|
||||||
LoginPolicy: &domain.LoginPolicy{
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
|
||||||
|
SecondFactorCheckLifetime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user: &user_model.UserView{
|
user: &user_model.UserView{
|
||||||
@ -1539,11 +1539,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
repo := &AuthRequestRepo{
|
repo := &AuthRequestRepo{}
|
||||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
|
||||||
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
|
|
||||||
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
|
|
||||||
}
|
|
||||||
got, ok, err := repo.mfaChecked(tt.args.userSession, tt.args.request, tt.args.user)
|
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) {
|
if (tt.errFunc != nil && !tt.errFunc(err)) || (err != nil && tt.errFunc == nil) {
|
||||||
t.Errorf("got wrong err: %v ", err)
|
t.Errorf("got wrong err: %v ", err)
|
||||||
@ -1563,6 +1559,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
user *user_model.UserView
|
user *user_model.UserView
|
||||||
|
request *domain.AuthRequest
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -1574,51 +1571,58 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
|
|||||||
"mfa set up, true",
|
"mfa set up, true",
|
||||||
fields{},
|
fields{},
|
||||||
args{
|
args{
|
||||||
&user_model.UserView{
|
user: &user_model.UserView{
|
||||||
HumanView: &user_model.HumanView{
|
HumanView: &user_model.HumanView{
|
||||||
MFAMaxSetUp: model.MFALevelSecondFactor,
|
MFAMaxSetUp: model.MFALevelSecondFactor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
request: &domain.AuthRequest{
|
||||||
|
LoginPolicy: &domain.LoginPolicy{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mfa skipped active, true",
|
"mfa skipped active, true",
|
||||||
fields{
|
fields{},
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
&user_model.UserView{
|
user: &user_model.UserView{
|
||||||
HumanView: &user_model.HumanView{
|
HumanView: &user_model.HumanView{
|
||||||
MFAMaxSetUp: -1,
|
MFAMaxSetUp: -1,
|
||||||
MFAInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
|
MFAInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
request: &domain.AuthRequest{
|
||||||
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mfa skipped inactive, false",
|
"mfa skipped inactive, false",
|
||||||
fields{
|
fields{},
|
||||||
MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
|
|
||||||
},
|
|
||||||
args{
|
args{
|
||||||
&user_model.UserView{
|
user: &user_model.UserView{
|
||||||
HumanView: &user_model.HumanView{
|
HumanView: &user_model.HumanView{
|
||||||
MFAMaxSetUp: -1,
|
MFAMaxSetUp: -1,
|
||||||
MFAInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
|
MFAInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
request: &domain.AuthRequest{
|
||||||
|
LoginPolicy: &domain.LoginPolicy{
|
||||||
|
MFAInitSkipLifetime: 30 * 24 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
repo := &AuthRequestRepo{
|
repo := &AuthRequestRepo{}
|
||||||
MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
|
if got := repo.mfaSkippedOrSetUp(tt.args.user, tt.args.request); got != tt.want {
|
||||||
}
|
|
||||||
if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want {
|
|
||||||
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)
|
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -92,11 +92,6 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, command *command.Comma
|
|||||||
ProjectProvider: queryView,
|
ProjectProvider: queryView,
|
||||||
ApplicationProvider: queries,
|
ApplicationProvider: queries,
|
||||||
IdGenerator: idGenerator,
|
IdGenerator: idGenerator,
|
||||||
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck,
|
|
||||||
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck,
|
|
||||||
MFAInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MFAInitSkip,
|
|
||||||
SecondFactorCheckLifeTime: systemDefaults.VerificationLifetimes.SecondFactorCheck,
|
|
||||||
MultiFactorCheckLifeTime: systemDefaults.VerificationLifetimes.MultiFactorCheck,
|
|
||||||
},
|
},
|
||||||
eventstore.TokenRepo{
|
eventstore.TokenRepo{
|
||||||
View: view,
|
View: view,
|
||||||
|
@ -42,6 +42,11 @@ func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy {
|
|||||||
HidePasswordReset: wm.HidePasswordReset,
|
HidePasswordReset: wm.HidePasswordReset,
|
||||||
ForceMFA: wm.ForceMFA,
|
ForceMFA: wm.ForceMFA,
|
||||||
PasswordlessType: wm.PasswordlessType,
|
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 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) {
|
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 {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
|
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 {
|
if !hasChanged {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
@ -65,6 +66,11 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
|||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset bool,
|
hidePasswordReset bool,
|
||||||
passwordlessType domain.PasswordlessType,
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
) (*iam.LoginPolicyChangedEvent, bool) {
|
) (*iam.LoginPolicyChangedEvent, bool) {
|
||||||
|
|
||||||
changes := make([]policy.LoginPolicyChanges, 0)
|
changes := make([]policy.LoginPolicyChanges, 0)
|
||||||
@ -86,6 +92,21 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
|
|||||||
if wm.HidePasswordReset != hidePasswordReset {
|
if wm.HidePasswordReset != hidePasswordReset {
|
||||||
changes = append(changes, policy.ChangeHidePasswordReset(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 {
|
if len(changes) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
@ -49,6 +50,11 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -98,6 +109,11 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -112,6 +128,11 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -201,6 +227,11 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -222,13 +253,29 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
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),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -243,6 +290,11 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: false,
|
ForceMFA: false,
|
||||||
HidePasswordReset: false,
|
HidePasswordReset: false,
|
||||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
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{
|
res: res{
|
||||||
@ -257,6 +309,11 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: false,
|
ForceMFA: false,
|
||||||
HidePasswordReset: false,
|
HidePasswordReset: false,
|
||||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
event, _ := iam.NewLoginPolicyChangedEvent(ctx,
|
||||||
&iam.NewAggregate().Aggregate,
|
&iam.NewAggregate().Aggregate,
|
||||||
[]policy.LoginPolicyChanges{
|
[]policy.LoginPolicyChanges{
|
||||||
@ -1293,6 +1392,11 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow
|
|||||||
policy.ChangeAllowUserNamePassword(allowUsernamePassword),
|
policy.ChangeAllowUserNamePassword(allowUsernamePassword),
|
||||||
policy.ChangeHidePasswordReset(hidePasswordReset),
|
policy.ChangeHidePasswordReset(hidePasswordReset),
|
||||||
policy.ChangePasswordlessType(passwordlessType),
|
policy.ChangePasswordlessType(passwordlessType),
|
||||||
|
policy.ChangePasswordCheckLifetime(passwordLifetime),
|
||||||
|
policy.ChangeExternalLoginCheckLifetime(externalLoginLifetime),
|
||||||
|
policy.ChangeMFAInitSkipLifetime(mfaInitSkipLifetime),
|
||||||
|
policy.ChangeSecondFactorCheckLifetime(secondFactorLifetime),
|
||||||
|
policy.ChangeMultiFactorCheckLifetime(multiFactorLifetime),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return event
|
return event
|
||||||
|
@ -241,7 +241,19 @@ func (c *Commands) setAllowedLoginPolicy(ctx context.Context, orgID string, feat
|
|||||||
if !features.LoginPolicyPasswordReset && defaultPolicy.HidePasswordReset != existingPolicy.HidePasswordReset {
|
if !features.LoginPolicyPasswordReset && defaultPolicy.HidePasswordReset != existingPolicy.HidePasswordReset {
|
||||||
policy.HidePasswordReset = defaultPolicy.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 {
|
if hasChanged {
|
||||||
events = append(events, changedEvent)
|
events = append(events, changedEvent)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
"github.com/caos/zitadel/internal/static/mock"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
@ -16,9 +18,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/features"
|
"github.com/caos/zitadel/internal/repository/features"
|
||||||
"github.com/caos/zitadel/internal/repository/iam"
|
"github.com/caos/zitadel/internal/repository/iam"
|
||||||
"github.com/caos/zitadel/internal/repository/org"
|
"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"
|
||||||
"github.com/caos/zitadel/internal/static/mock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||||
@ -165,6 +165,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
@ -1002,6 +1027,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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),
|
org.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.MultiFactorTypeU2FWithPIN),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
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(
|
eventFromEventPusher(
|
||||||
org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||||
@ -1278,6 +1319,11 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeAllowed,
|
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.AllowExternalIDP,
|
||||||
policy.ForceMFA,
|
policy.ForceMFA,
|
||||||
policy.HidePasswordReset,
|
policy.HidePasswordReset,
|
||||||
policy.PasswordlessType))
|
policy.PasswordlessType,
|
||||||
|
policy.PasswordCheckLifetime,
|
||||||
|
policy.ExternalLoginCheckLifetime,
|
||||||
|
policy.MFAInitSkipLifetime,
|
||||||
|
policy.SecondFactorCheckLifetime,
|
||||||
|
policy.MultiFactorCheckLifetime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -100,7 +105,12 @@ func (c *Commands) ChangeLoginPolicy(ctx context.Context, resourceOwner string,
|
|||||||
policy.AllowExternalIDP,
|
policy.AllowExternalIDP,
|
||||||
policy.ForceMFA,
|
policy.ForceMFA,
|
||||||
policy.HidePasswordReset,
|
policy.HidePasswordReset,
|
||||||
policy.PasswordlessType)
|
policy.PasswordlessType,
|
||||||
|
policy.PasswordCheckLifetime,
|
||||||
|
policy.ExternalLoginCheckLifetime,
|
||||||
|
policy.MFAInitSkipLifetime,
|
||||||
|
policy.SecondFactorCheckLifetime,
|
||||||
|
policy.MultiFactorCheckLifetime)
|
||||||
|
|
||||||
if !hasChanged {
|
if !hasChanged {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
|
||||||
|
@ -2,6 +2,7 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
@ -68,6 +69,11 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
|||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset bool,
|
hidePasswordReset bool,
|
||||||
passwordlessType domain.PasswordlessType,
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
) (*org.LoginPolicyChangedEvent, bool) {
|
) (*org.LoginPolicyChangedEvent, bool) {
|
||||||
|
|
||||||
changes := make([]policy.LoginPolicyChanges, 0)
|
changes := make([]policy.LoginPolicyChanges, 0)
|
||||||
@ -86,6 +92,21 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
|
|||||||
if wm.HidePasswordReset != hidePasswordReset {
|
if wm.HidePasswordReset != hidePasswordReset {
|
||||||
changes = append(changes, policy.ChangeHidePasswordReset(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 {
|
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
|
||||||
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
|
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@ -17,6 +18,14 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/user"
|
"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) {
|
func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
@ -71,6 +80,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -85,6 +99,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
AllowExternalIDP: true,
|
AllowExternalIDP: true,
|
||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -107,6 +126,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -122,6 +146,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
AllowExternalIDP: true,
|
AllowExternalIDP: true,
|
||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -144,6 +173,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -175,6 +214,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -189,6 +233,11 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -320,6 +379,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
AllowExternalIDP: true,
|
AllowExternalIDP: true,
|
||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -341,6 +405,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -370,6 +444,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: true,
|
ForceMFA: true,
|
||||||
HidePasswordReset: true,
|
HidePasswordReset: true,
|
||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
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{
|
res: res{
|
||||||
@ -391,6 +470,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
domain.PasswordlessTypeNotAllowed,
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -426,6 +528,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
AllowExternalIDP: false,
|
AllowExternalIDP: false,
|
||||||
ForceMFA: false,
|
ForceMFA: false,
|
||||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
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{
|
res: res{
|
||||||
@ -440,6 +547,11 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
|
|||||||
ForceMFA: false,
|
ForceMFA: false,
|
||||||
HidePasswordReset: false,
|
HidePasswordReset: false,
|
||||||
PasswordlessType: domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
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,
|
||||||
event, _ := org.NewLoginPolicyChangedEvent(ctx,
|
passwordlessType domain.PasswordlessType,
|
||||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
passwordLifetime, externalLoginLifetime, mfaInitSkipLifetime, secondFactorLifetime, multiFactorLifetime *time.Duration) *org.LoginPolicyChangedEvent {
|
||||||
[]policy.LoginPolicyChanges{
|
changes := []policy.LoginPolicyChanges{
|
||||||
policy.ChangeAllowUserNamePassword(usernamePassword),
|
policy.ChangeAllowUserNamePassword(usernamePassword),
|
||||||
policy.ChangeAllowRegister(register),
|
policy.ChangeAllowRegister(register),
|
||||||
policy.ChangeAllowExternalIDP(externalIDP),
|
policy.ChangeAllowExternalIDP(externalIDP),
|
||||||
policy.ChangeForceMFA(mfa),
|
policy.ChangeForceMFA(mfa),
|
||||||
policy.ChangeHidePasswordReset(passwordReset),
|
policy.ChangeHidePasswordReset(passwordReset),
|
||||||
policy.ChangePasswordlessType(passwordlessType),
|
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,
|
||||||
|
changes,
|
||||||
)
|
)
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/repository/policy"
|
"github.com/caos/zitadel/internal/repository/policy"
|
||||||
@ -15,6 +17,11 @@ type LoginPolicyWriteModel struct {
|
|||||||
ForceMFA bool
|
ForceMFA bool
|
||||||
HidePasswordReset bool
|
HidePasswordReset bool
|
||||||
PasswordlessType domain.PasswordlessType
|
PasswordlessType domain.PasswordlessType
|
||||||
|
PasswordCheckLifetime time.Duration
|
||||||
|
ExternalLoginCheckLifetime time.Duration
|
||||||
|
MFAInitSkipLifetime time.Duration
|
||||||
|
SecondFactorCheckLifetime time.Duration
|
||||||
|
MultiFactorCheckLifetime time.Duration
|
||||||
State domain.PolicyState
|
State domain.PolicyState
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +35,11 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
|||||||
wm.ForceMFA = e.ForceMFA
|
wm.ForceMFA = e.ForceMFA
|
||||||
wm.PasswordlessType = e.PasswordlessType
|
wm.PasswordlessType = e.PasswordlessType
|
||||||
wm.HidePasswordReset = e.HidePasswordReset
|
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
|
wm.State = domain.PolicyStateActive
|
||||||
case *policy.LoginPolicyChangedEvent:
|
case *policy.LoginPolicyChangedEvent:
|
||||||
if e.AllowRegister != nil {
|
if e.AllowRegister != nil {
|
||||||
@ -48,6 +60,21 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
|
|||||||
if e.PasswordlessType != nil {
|
if e.PasswordlessType != nil {
|
||||||
wm.PasswordlessType = *e.PasswordlessType
|
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:
|
case *policy.LoginPolicyRemovedEvent:
|
||||||
wm.State = domain.PolicyStateRemoved
|
wm.State = domain.PolicyStateRemoved
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1157,11 @@ func TestCommandSide_CheckPassword(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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,
|
||||||
false,
|
false,
|
||||||
domain.PasswordlessTypeNotAllowed,
|
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
|
SMTPPasswordVerificationKey *crypto.KeyConfig
|
||||||
SMSVerificationKey *crypto.KeyConfig
|
SMSVerificationKey *crypto.KeyConfig
|
||||||
Multifactors MultifactorConfig
|
Multifactors MultifactorConfig
|
||||||
VerificationLifetimes VerificationLifetimes
|
|
||||||
DomainVerification DomainVerification
|
DomainVerification DomainVerification
|
||||||
Notifications Notifications
|
Notifications Notifications
|
||||||
KeyConfig KeyConfig
|
KeyConfig KeyConfig
|
||||||
@ -49,14 +48,6 @@ type OTPConfig struct {
|
|||||||
VerificationKey *crypto.KeyConfig
|
VerificationKey *crypto.KeyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationLifetimes struct {
|
|
||||||
PasswordCheck time.Duration
|
|
||||||
ExternalLoginCheck time.Duration
|
|
||||||
MFAInitSkip time.Duration
|
|
||||||
SecondFactorCheck time.Duration
|
|
||||||
MultiFactorCheck time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type DomainVerification struct {
|
type DomainVerification struct {
|
||||||
VerificationKey *crypto.KeyConfig
|
VerificationKey *crypto.KeyConfig
|
||||||
VerificationGenerator crypto.GeneratorConfig
|
VerificationGenerator crypto.GeneratorConfig
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import "github.com/caos/zitadel/internal/eventstore/v1/models"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
|
)
|
||||||
|
|
||||||
type LoginPolicy struct {
|
type LoginPolicy struct {
|
||||||
models.ObjectRoot
|
models.ObjectRoot
|
||||||
@ -15,6 +19,11 @@ type LoginPolicy struct {
|
|||||||
MultiFactors []MultiFactorType
|
MultiFactors []MultiFactorType
|
||||||
PasswordlessType PasswordlessType
|
PasswordlessType PasswordlessType
|
||||||
HidePasswordReset bool
|
HidePasswordReset bool
|
||||||
|
PasswordCheckLifetime time.Duration
|
||||||
|
ExternalLoginCheckLifetime time.Duration
|
||||||
|
MFAInitSkipLifetime time.Duration
|
||||||
|
SecondFactorCheckLifetime time.Duration
|
||||||
|
MultiFactorCheckLifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type IDPProvider struct {
|
type IDPProvider struct {
|
||||||
|
@ -27,6 +27,11 @@ type LoginPolicy struct {
|
|||||||
PasswordlessType domain.PasswordlessType
|
PasswordlessType domain.PasswordlessType
|
||||||
IsDefault bool
|
IsDefault bool
|
||||||
HidePasswordReset bool
|
HidePasswordReset bool
|
||||||
|
PasswordCheckLifetime time.Duration
|
||||||
|
ExternalLoginCheckLifetime time.Duration
|
||||||
|
MFAInitSkipLifetime time.Duration
|
||||||
|
SecondFactorCheckLifetime time.Duration
|
||||||
|
MultiFactorCheckLifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type SecondFactors struct {
|
type SecondFactors struct {
|
||||||
@ -95,6 +100,26 @@ var (
|
|||||||
name: projection.LoginPolicyHidePWResetCol,
|
name: projection.LoginPolicyHidePWResetCol,
|
||||||
table: loginPolicyTable,
|
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) {
|
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(),
|
LoginPolicyColumnPasswordlessType.identifier(),
|
||||||
LoginPolicyColumnIsDefault.identifier(),
|
LoginPolicyColumnIsDefault.identifier(),
|
||||||
LoginPolicyColumnHidePasswordReset.identifier(),
|
LoginPolicyColumnHidePasswordReset.identifier(),
|
||||||
|
LoginPolicyColumnPasswordCheckLifetime.identifier(),
|
||||||
|
LoginPolicyColumnExternalLoginCheckLifetime.identifier(),
|
||||||
|
LoginPolicyColumnMFAInitSkipLifetime.identifier(),
|
||||||
|
LoginPolicyColumnSecondFactorCheckLifetime.identifier(),
|
||||||
|
LoginPolicyColumnMultiFacotrCheckLifetime.identifier(),
|
||||||
).From(loginPolicyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
).From(loginPolicyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||||
func(row *sql.Row) (*LoginPolicy, error) {
|
func(row *sql.Row) (*LoginPolicy, error) {
|
||||||
p := new(LoginPolicy)
|
p := new(LoginPolicy)
|
||||||
@ -253,6 +283,11 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy,
|
|||||||
&p.PasswordlessType,
|
&p.PasswordlessType,
|
||||||
&p.IsDefault,
|
&p.IsDefault,
|
||||||
&p.HidePasswordReset,
|
&p.HidePasswordReset,
|
||||||
|
&p.PasswordCheckLifetime,
|
||||||
|
&p.ExternalLoginCheckLifetime,
|
||||||
|
&p.MFAInitSkipLifetime,
|
||||||
|
&p.SecondFactorCheckLifetime,
|
||||||
|
&p.MultiFactorCheckLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errs.Is(err, sql.ErrNoRows) {
|
if errs.Is(err, sql.ErrNoRows) {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
errs "github.com/caos/zitadel/internal/errors"
|
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.multi_factors,`+
|
||||||
` zitadel.projections.login_policies.passwordless_type,`+
|
` zitadel.projections.login_policies.passwordless_type,`+
|
||||||
` zitadel.projections.login_policies.is_default,`+
|
` 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`),
|
` FROM zitadel.projections.login_policies`),
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -72,7 +78,12 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
|||||||
` zitadel.projections.login_policies.multi_factors,`+
|
` zitadel.projections.login_policies.multi_factors,`+
|
||||||
` zitadel.projections.login_policies.passwordless_type,`+
|
` zitadel.projections.login_policies.passwordless_type,`+
|
||||||
` zitadel.projections.login_policies.is_default,`+
|
` 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`),
|
` FROM zitadel.projections.login_policies`),
|
||||||
[]string{
|
[]string{
|
||||||
"aggregate_id",
|
"aggregate_id",
|
||||||
@ -88,6 +99,11 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
|||||||
"passwordless_type",
|
"passwordless_type",
|
||||||
"is_default",
|
"is_default",
|
||||||
"hide_password_reset",
|
"hide_password_reset",
|
||||||
|
"password_check_lifetime",
|
||||||
|
"external_login_check_lifetime",
|
||||||
|
"mfa_init_skip_lifetime",
|
||||||
|
"second_factor_check_lifetime",
|
||||||
|
"multi_factor_check_lifetime",
|
||||||
},
|
},
|
||||||
[]driver.Value{
|
[]driver.Value{
|
||||||
"ro",
|
"ro",
|
||||||
@ -103,6 +119,11 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
|||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
time.Hour * 2,
|
||||||
|
time.Hour * 2,
|
||||||
|
time.Hour * 2,
|
||||||
|
time.Hour * 2,
|
||||||
|
time.Hour * 2,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -120,6 +141,11 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
|||||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||||
IsDefault: true,
|
IsDefault: true,
|
||||||
HidePasswordReset: 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.multi_factors,`+
|
||||||
` zitadel.projections.login_policies.passwordless_type,`+
|
` zitadel.projections.login_policies.passwordless_type,`+
|
||||||
` zitadel.projections.login_policies.is_default,`+
|
` 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`),
|
` FROM zitadel.projections.login_policies`),
|
||||||
sql.ErrConnDone,
|
sql.ErrConnDone,
|
||||||
),
|
),
|
||||||
|
@ -111,6 +111,11 @@ const (
|
|||||||
LoginPolicyPasswordlessTypeCol = "passwordless_type"
|
LoginPolicyPasswordlessTypeCol = "passwordless_type"
|
||||||
LoginPolicyIsDefaultCol = "is_default"
|
LoginPolicyIsDefaultCol = "is_default"
|
||||||
LoginPolicyHidePWResetCol = "hide_password_reset"
|
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) {
|
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(LoginPolicyPasswordlessTypeCol, policyEvent.PasswordlessType),
|
||||||
handler.NewCol(LoginPolicyIsDefaultCol, isDefault),
|
handler.NewCol(LoginPolicyIsDefaultCol, isDefault),
|
||||||
handler.NewCol(LoginPolicyHidePWResetCol, policyEvent.HidePasswordReset),
|
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
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +187,22 @@ func (p *LoginPolicyProjection) reduceLoginPolicyChanged(event eventstore.Event)
|
|||||||
if policyEvent.HidePasswordReset != nil {
|
if policyEvent.HidePasswordReset != nil {
|
||||||
cols = append(cols, handler.NewCol(LoginPolicyHidePWResetCol, *policyEvent.HidePasswordReset))
|
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(
|
return crdb.NewUpdateStatement(
|
||||||
&policyEvent,
|
&policyEvent,
|
||||||
cols,
|
cols,
|
||||||
|
@ -2,6 +2,7 @@ package projection
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
@ -34,8 +35,13 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
"allowExternalIdp": false,
|
"allowExternalIdp": false,
|
||||||
"forceMFA": false,
|
"forceMFA": false,
|
||||||
"hidePasswordReset": true,
|
"hidePasswordReset": true,
|
||||||
"passwordlessType": 1
|
"passwordlessType": 1,
|
||||||
}`),
|
"passwordCheckLifetime": 10000000,
|
||||||
|
"externalLoginCheckLifetime": 10000000,
|
||||||
|
"mfaInitSkipLifetime": 10000000,
|
||||||
|
"secondFactorCheckLifetime": 10000000,
|
||||||
|
"multiFactorCheckLifetime": 10000000
|
||||||
|
}`),
|
||||||
), org.LoginPolicyAddedEventMapper),
|
), org.LoginPolicyAddedEventMapper),
|
||||||
},
|
},
|
||||||
reduce: (&LoginPolicyProjection{}).reduceLoginPolicyAdded,
|
reduce: (&LoginPolicyProjection{}).reduceLoginPolicyAdded,
|
||||||
@ -47,7 +53,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
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{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -60,6 +66,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -79,8 +90,13 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
"allowExternalIdp": true,
|
"allowExternalIdp": true,
|
||||||
"forceMFA": true,
|
"forceMFA": true,
|
||||||
"hidePasswordReset": true,
|
"hidePasswordReset": true,
|
||||||
"passwordlessType": 1
|
"passwordlessType": 1,
|
||||||
}`),
|
"passwordCheckLifetime": 10000000,
|
||||||
|
"externalLoginCheckLifetime": 10000000,
|
||||||
|
"mfaInitSkipLifetime": 10000000,
|
||||||
|
"secondFactorCheckLifetime": 10000000,
|
||||||
|
"multiFactorCheckLifetime": 10000000
|
||||||
|
}`),
|
||||||
), org.LoginPolicyChangedEventMapper),
|
), org.LoginPolicyChangedEventMapper),
|
||||||
},
|
},
|
||||||
want: wantReduce{
|
want: wantReduce{
|
||||||
@ -91,7 +107,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
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{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -101,6 +117,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
true,
|
true,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
"agg-id",
|
"agg-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -276,7 +297,12 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
"allowExternalIdp": false,
|
"allowExternalIdp": false,
|
||||||
"forceMFA": false,
|
"forceMFA": false,
|
||||||
"hidePasswordReset": true,
|
"hidePasswordReset": true,
|
||||||
"passwordlessType": 1
|
"passwordlessType": 1,
|
||||||
|
"passwordCheckLifetime": 10000000,
|
||||||
|
"externalLoginCheckLifetime": 10000000,
|
||||||
|
"mfaInitSkipLifetime": 10000000,
|
||||||
|
"secondFactorCheckLifetime": 10000000,
|
||||||
|
"multiFactorCheckLifetime": 10000000
|
||||||
}`),
|
}`),
|
||||||
), iam.LoginPolicyAddedEventMapper),
|
), iam.LoginPolicyAddedEventMapper),
|
||||||
},
|
},
|
||||||
@ -288,7 +314,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
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{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -301,6 +327,11 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
|
|||||||
domain.PasswordlessTypeAllowed,
|
domain.PasswordlessTypeAllowed,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
|
time.Millisecond * 10,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,7 @@ package iam
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
@ -28,6 +29,11 @@ func NewLoginPolicyAddedEvent(
|
|||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset bool,
|
hidePasswordReset bool,
|
||||||
passwordlessType domain.PasswordlessType,
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
) *LoginPolicyAddedEvent {
|
) *LoginPolicyAddedEvent {
|
||||||
return &LoginPolicyAddedEvent{
|
return &LoginPolicyAddedEvent{
|
||||||
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
||||||
@ -40,7 +46,12 @@ func NewLoginPolicyAddedEvent(
|
|||||||
allowExternalIDP,
|
allowExternalIDP,
|
||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset,
|
hidePasswordReset,
|
||||||
passwordlessType),
|
passwordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package org
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
@ -29,6 +30,11 @@ func NewLoginPolicyAddedEvent(
|
|||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset bool,
|
hidePasswordReset bool,
|
||||||
passwordlessType domain.PasswordlessType,
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
) *LoginPolicyAddedEvent {
|
) *LoginPolicyAddedEvent {
|
||||||
return &LoginPolicyAddedEvent{
|
return &LoginPolicyAddedEvent{
|
||||||
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
LoginPolicyAddedEvent: *policy.NewLoginPolicyAddedEvent(
|
||||||
@ -41,7 +47,12 @@ func NewLoginPolicyAddedEvent(
|
|||||||
allowExternalIDP,
|
allowExternalIDP,
|
||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset,
|
hidePasswordReset,
|
||||||
passwordlessType),
|
passwordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package policy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
@ -25,6 +26,11 @@ type LoginPolicyAddedEvent struct {
|
|||||||
ForceMFA bool `json:"forceMFA,omitempty"`
|
ForceMFA bool `json:"forceMFA,omitempty"`
|
||||||
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
|
HidePasswordReset bool `json:"hidePasswordReset,omitempty"`
|
||||||
PasswordlessType domain.PasswordlessType `json:"passwordlessType,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{} {
|
func (e *LoginPolicyAddedEvent) Data() interface{} {
|
||||||
@ -43,6 +49,11 @@ func NewLoginPolicyAddedEvent(
|
|||||||
forceMFA,
|
forceMFA,
|
||||||
hidePasswordReset bool,
|
hidePasswordReset bool,
|
||||||
passwordlessType domain.PasswordlessType,
|
passwordlessType domain.PasswordlessType,
|
||||||
|
passwordCheckLifetime,
|
||||||
|
externalLoginCheckLifetime,
|
||||||
|
mfaInitSkipLifetime,
|
||||||
|
secondFactorCheckLifetime,
|
||||||
|
multiFactorCheckLifetime time.Duration,
|
||||||
) *LoginPolicyAddedEvent {
|
) *LoginPolicyAddedEvent {
|
||||||
return &LoginPolicyAddedEvent{
|
return &LoginPolicyAddedEvent{
|
||||||
BaseEvent: *base,
|
BaseEvent: *base,
|
||||||
@ -52,6 +63,11 @@ func NewLoginPolicyAddedEvent(
|
|||||||
ForceMFA: forceMFA,
|
ForceMFA: forceMFA,
|
||||||
PasswordlessType: passwordlessType,
|
PasswordlessType: passwordlessType,
|
||||||
HidePasswordReset: hidePasswordReset,
|
HidePasswordReset: hidePasswordReset,
|
||||||
|
PasswordCheckLifetime: passwordCheckLifetime,
|
||||||
|
ExternalLoginCheckLifetime: externalLoginCheckLifetime,
|
||||||
|
MFAInitSkipLifetime: mfaInitSkipLifetime,
|
||||||
|
SecondFactorCheckLifetime: secondFactorCheckLifetime,
|
||||||
|
MultiFactorCheckLifetime: multiFactorCheckLifetime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +93,11 @@ type LoginPolicyChangedEvent struct {
|
|||||||
ForceMFA *bool `json:"forceMFA,omitempty"`
|
ForceMFA *bool `json:"forceMFA,omitempty"`
|
||||||
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
||||||
PasswordlessType *domain.PasswordlessType `json:"passwordlessType,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{} {
|
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) {
|
func LoginPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||||
e := &LoginPolicyChangedEvent{
|
e := &LoginPolicyChangedEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
|
@ -3459,6 +3459,11 @@ message UpdateLoginPolicyRequest {
|
|||||||
description: "defines if password reset link should be shown in the login screen"
|
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 {
|
message UpdateLoginPolicyResponse {
|
||||||
|
@ -4397,6 +4397,11 @@ message AddCustomLoginPolicyRequest {
|
|||||||
bool force_mfa = 4;
|
bool force_mfa = 4;
|
||||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||||
bool hide_password_reset = 6;
|
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 {
|
message AddCustomLoginPolicyResponse {
|
||||||
@ -4410,6 +4415,11 @@ message UpdateCustomLoginPolicyRequest {
|
|||||||
bool force_mfa = 4;
|
bool force_mfa = 4;
|
||||||
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
zitadel.policy.v1.PasswordlessType passwordless_type = 5 [(validate.rules).enum = {defined_only: true}];
|
||||||
bool hide_password_reset = 6;
|
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 {
|
message UpdateCustomLoginPolicyResponse {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
import "zitadel/object.proto";
|
import "zitadel/object.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
|
||||||
package zitadel.policy.v1;
|
package zitadel.policy.v1;
|
||||||
@ -128,6 +129,12 @@ message LoginPolicy {
|
|||||||
description: "defines if password reset link should be shown in the login screen"
|
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 {
|
enum SecondFactorType {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user