feat: allow to force MFA local only (#6234)

This PR adds an option to the LoginPolicy to "Force MFA for local users", so that users authenticated through an IDP must not configure (and verify) an MFA.
This commit is contained in:
Livio Spring
2023-07-20 06:06:16 +02:00
committed by GitHub
parent 1c3a15ff57
commit fed15574f6
49 changed files with 488 additions and 94 deletions

View File

@@ -70,6 +70,7 @@ type InstanceSetup struct {
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
ForceMFALocalOnly bool
HidePasswordReset bool
IgnoreUnknownUsername bool
AllowDomainDiscovery bool
@@ -226,6 +227,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LoginPolicy.AllowRegister,
setup.LoginPolicy.AllowExternalIDP,
setup.LoginPolicy.ForceMFA,
setup.LoginPolicy.ForceMFALocalOnly,
setup.LoginPolicy.HidePasswordReset,
setup.LoginPolicy.IgnoreUnknownUsername,
setup.LoginPolicy.AllowDomainDiscovery,

View File

@@ -34,6 +34,7 @@ func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy {
IgnoreUnknownUsernames: wm.IgnoreUnknownUsernames,
AllowDomainDiscovery: wm.AllowDomainDiscovery,
ForceMFA: wm.ForceMFA,
ForceMFALocalOnly: wm.ForceMFALocalOnly,
PasswordlessType: wm.PasswordlessType,
DefaultRedirectURI: wm.DefaultRedirectURI,
PasswordCheckLifetime: wm.PasswordCheckLifetime,
@@ -123,10 +124,10 @@ func writeModelToLockoutPolicy(wm *LockoutPolicyWriteModel) *domain.LockoutPolic
func writeModelToPrivacyPolicy(wm *PrivacyPolicyWriteModel) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
SupportEmail: wm.SupportEmail,
}
}

View File

@@ -234,6 +234,7 @@ func prepareChangeDefaultLoginPolicy(a *instance.Aggregate, policy *ChangeLoginP
policy.AllowRegister,
policy.AllowExternalIDP,
policy.ForceMFA,
policy.ForceMFALocalOnly,
policy.HidePasswordReset,
policy.IgnoreUnknownUsernames,
policy.AllowDomainDiscovery,
@@ -260,6 +261,7 @@ func prepareAddDefaultLoginPolicy(
allowRegister bool,
allowExternalIDP bool,
forceMFA bool,
forceMFALocalOnly bool,
hidePasswordReset bool,
ignoreUnknownUsernames bool,
allowDomainDiscovery bool,
@@ -293,6 +295,7 @@ func prepareAddDefaultLoginPolicy(
allowRegister,
allowExternalIDP,
forceMFA,
forceMFALocalOnly,
hidePasswordReset,
ignoreUnknownUsernames,
allowDomainDiscovery,

View File

@@ -65,6 +65,7 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent(
allowRegister,
allowExternalIDP,
forceMFA,
forceMFALocalOnly,
hidePasswordReset,
ignoreUnknownUsernames,
allowDomainDiscovery,
@@ -92,6 +93,9 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent(
if wm.ForceMFA != forceMFA {
changes = append(changes, policy.ChangeForceMFA(forceMFA))
}
if wm.ForceMFALocalOnly != forceMFALocalOnly {
changes = append(changes, policy.ChangeForceMFALocalOnly(forceMFALocalOnly))
}
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
}

View File

@@ -73,6 +73,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -92,6 +93,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -129,6 +131,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -153,6 +156,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*10,
@@ -172,6 +176,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) {
AllowUsernamePassword: false,
AllowExternalIDP: false,
ForceMFA: false,
ForceMFALocalOnly: false,
HidePasswordReset: false,
IgnoreUnknownUsernames: false,
AllowDomainDiscovery: false,
@@ -281,6 +286,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -322,6 +328,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -383,6 +390,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -526,6 +534,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -567,6 +576,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -621,6 +631,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -680,6 +691,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -747,6 +759,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1301,7 +1314,7 @@ func TestCommandSide_RemoveMultiFactorDefaultLoginPolicy(t *testing.T) {
}
}
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA,
func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, forceMFALocalOnly,
hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, disableLoginWithEmail, disableLoginWithPhone bool,
passwordlessType domain.PasswordlessType,
redirectURI string,
@@ -1312,6 +1325,7 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow
policy.ChangeAllowRegister(allowRegister),
policy.ChangeAllowExternalIDP(allowExternalIDP),
policy.ChangeForceMFA(forceMFA),
policy.ChangeForceMFALocalOnly(forceMFALocalOnly),
policy.ChangeAllowUserNamePassword(allowUsernamePassword),
policy.ChangeHidePasswordReset(hidePasswordReset),
policy.ChangeIgnoreUnknownUsernames(ignoreUnknownUsernames),

View File

@@ -21,6 +21,7 @@ type AddLoginPolicy struct {
AllowExternalIDP bool
IDPProviders []*AddLoginPolicyIDP
ForceMFA bool
ForceMFALocalOnly bool
SecondFactors []domain.SecondFactorType
MultiFactors []domain.MultiFactorType
PasswordlessType domain.PasswordlessType
@@ -47,6 +48,7 @@ type ChangeLoginPolicy struct {
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
ForceMFALocalOnly bool
PasswordlessType domain.PasswordlessType
HidePasswordReset bool
IgnoreUnknownUsernames bool
@@ -425,6 +427,7 @@ func prepareAddLoginPolicy(a *org.Aggregate, policy *AddLoginPolicy) preparation
policy.AllowRegister,
policy.AllowExternalIDP,
policy.ForceMFA,
policy.ForceMFALocalOnly,
policy.HidePasswordReset,
policy.IgnoreUnknownUsernames,
policy.AllowDomainDiscovery,

View File

@@ -61,6 +61,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
true,
false,
false,
domain.PasswordlessTypeAllowed,
@@ -83,6 +84,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
@@ -118,6 +120,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -139,6 +142,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -174,6 +178,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -213,6 +218,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -246,6 +252,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -285,6 +292,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -341,6 +349,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -369,6 +378,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -450,6 +460,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
DisableLoginWithEmail: true,
@@ -480,6 +491,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -500,6 +512,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
ForceMFALocalOnly: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
AllowDomainDiscovery: true,
@@ -536,6 +549,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"https://example.com/redirect",
time.Hour*1,
@@ -581,6 +595,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) {
AllowUsernamePassword: false,
AllowExternalIDP: false,
ForceMFA: false,
ForceMFALocalOnly: false,
IgnoreUnknownUsernames: false,
AllowDomainDiscovery: false,
DisableLoginWithEmail: false,
@@ -686,6 +701,7 @@ func TestCommandSide_RemoveLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -829,6 +845,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -873,6 +890,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -937,6 +955,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1104,6 +1123,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1148,6 +1168,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1204,6 +1225,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1267,6 +1289,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,
@@ -1338,6 +1361,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
true,
true,
true,
true,
domain.PasswordlessTypeAllowed,
"",
time.Hour*1,

View File

@@ -15,6 +15,7 @@ type LoginPolicyWriteModel struct {
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
ForceMFALocalOnly bool
HidePasswordReset bool
IgnoreUnknownUsernames bool
AllowDomainDiscovery bool
@@ -38,6 +39,7 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
wm.AllowUserNamePassword = e.AllowUserNamePassword
wm.AllowExternalIDP = e.AllowExternalIDP
wm.ForceMFA = e.ForceMFA
wm.ForceMFALocalOnly = e.ForceMFALocalOnly
wm.PasswordlessType = e.PasswordlessType
wm.HidePasswordReset = e.HidePasswordReset
wm.IgnoreUnknownUsernames = e.IgnoreUnknownUsernames
@@ -64,6 +66,9 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
if e.ForceMFA != nil {
wm.ForceMFA = *e.ForceMFA
}
if e.ForceMFALocalOnly != nil {
wm.ForceMFALocalOnly = *e.ForceMFALocalOnly
}
if e.HidePasswordReset != nil {
wm.HidePasswordReset = *e.HidePasswordReset
}

View File

@@ -1182,6 +1182,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1222,6 +1223,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1263,6 +1265,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1320,6 +1323,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1406,6 +1410,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1499,6 +1504,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1582,6 +1588,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -1671,6 +1678,7 @@ func TestCommandSide_CheckPassword(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,

View File

@@ -2246,6 +2246,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2315,6 +2316,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2384,6 +2386,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2470,6 +2473,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2614,6 +2618,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2726,6 +2731,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2838,6 +2844,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -2944,6 +2951,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -3072,6 +3080,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,
@@ -3195,6 +3204,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
false,
false,
false,
false,
domain.PasswordlessTypeNotAllowed,
"",
time.Hour*1,