feat: enable otp email and sms (#6260)

* feat: enable otp email and sms

* feat: enable otp factors in login settings

* remove tests without value

* translate second factors

* don't add new factors yet

* add comment

* add factors to docs

* backward compatible settings api

* compile tests

* add available 2fa types

* test: add mapping tests

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Elio Bischof
2023-07-28 07:39:30 +02:00
committed by GitHub
parent d3e403f645
commit 31ec1d83b9
28 changed files with 696 additions and 124 deletions

View File

@@ -245,8 +245,12 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LoginPolicy.SecondFactorCheckLifetime,
setup.LoginPolicy.MultiFactorCheckLifetime,
),
prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTP),
prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeTOTP),
prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeU2F),
/* TODO: incomment when usable
prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTPEmail),
prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTPSMS),
*/
prepareAddMultiFactorToDefaultLoginPolicy(instanceAgg, domain.MultiFactorTypeU2FWithPIN),
prepareAddDefaultPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink, setup.PrivacyPolicy.SupportEmail),

View File

@@ -884,7 +884,7 @@ func TestCommandSide_AddSecondFactorDefaultLoginPolicy(t *testing.T) {
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -892,14 +892,14 @@ func TestCommandSide_AddSecondFactorDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
err: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "add factor, ok",
name: "add factor totp, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -910,7 +910,7 @@ func TestCommandSide_AddSecondFactorDefaultLoginPolicy(t *testing.T) {
"INSTANCE",
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP),
domain.SecondFactorTypeTOTP),
),
},
),
@@ -918,7 +918,98 @@ func TestCommandSide_AddSecondFactorDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
{
name: "add factor otp email, ok ",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPEmail),
),
},
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
factor: domain.SecondFactorTypeOTPEmail,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
{
name: "add factor otp sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
factor: domain.SecondFactorTypeOTPSMS,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
{
name: "add factor totp, add otp sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeTOTP,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
factor: domain.SecondFactorTypeOTPSMS,
},
res: res{
want: &domain.ObjectDetails{
@@ -989,14 +1080,14 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "factor removed, not found error",
name: "factor removed totp, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -1004,13 +1095,13 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -1018,14 +1109,14 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "add factor, ok",
name: "factor removed otp email, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -1033,7 +1124,65 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeOTPEmail,
),
),
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPEmail,
),
),
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPEmail,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "factor removed otp sms, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "remove factor totp, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -1042,7 +1191,7 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTP),
domain.SecondFactorTypeTOTP),
),
},
),
@@ -1050,7 +1199,7 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
want: &domain.ObjectDetails{
@@ -1058,6 +1207,97 @@ func TestCommandSide_RemoveSecondFactorDefaultLoginPolicy(t *testing.T) {
},
},
},
{
name: "remove factor email, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPEmail,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPEmail),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPEmail,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
{
name: "remove factor sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
instance.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
{
name: "factor added totp, removed otp sms, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
domain.SecondFactorTypeTOTP,
),
),
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
},
res: res{
err: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -231,7 +231,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
eventFromEventPusher(
@@ -265,7 +265,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) {
MFAInitSkipLifetime: time.Hour * 3,
SecondFactorCheckLifetime: time.Hour * 4,
MultiFactorCheckLifetime: time.Hour * 5,
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP},
SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeTOTP},
MultiFactors: []domain.MultiFactorType{domain.MultiFactorTypeU2FWithPIN},
},
},
@@ -1504,7 +1504,7 @@ func TestCommandSide_AddSecondFactorLoginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -1512,7 +1512,7 @@ func TestCommandSide_AddSecondFactorLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
resourceOwner: "org1",
},
res: res{
@@ -1520,7 +1520,7 @@ func TestCommandSide_AddSecondFactorLoginPolicy(t *testing.T) {
},
},
{
name: "add factor, ok",
name: "add factor totp, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -1530,7 +1530,7 @@ func TestCommandSide_AddSecondFactorLoginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP),
domain.SecondFactorTypeTOTP),
),
},
),
@@ -1538,11 +1538,96 @@ func TestCommandSide_AddSecondFactorLoginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
resourceOwner: "org1",
},
res: res{
want: domain.SecondFactorTypeOTP,
want: domain.SecondFactorTypeTOTP,
},
},
{
name: "add factor otp email, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPEmail),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPEmail,
resourceOwner: "org1",
},
res: res{
want: domain.SecondFactorTypeOTPEmail,
},
},
{
name: "add factor otp sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
resourceOwner: "org1",
},
res: res{
want: domain.SecondFactorTypeOTPSMS,
},
},
{
name: "add factor totp, add otp sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeTOTP,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
resourceOwner: "org1",
},
res: res{
want: domain.SecondFactorTypeOTPSMS,
},
},
}
@@ -1593,7 +1678,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
@@ -1624,7 +1709,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
resourceOwner: "org1",
},
res: res{
@@ -1632,7 +1717,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
},
{
name: "factor removed, not found error",
name: "factor totp removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -1640,13 +1725,13 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -1654,7 +1739,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
resourceOwner: "org1",
},
res: res{
@@ -1662,7 +1747,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
},
{
name: "add factor, ok",
name: "factor otp email removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
@@ -1670,7 +1755,67 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP,
domain.SecondFactorTypeOTPEmail,
),
),
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPEmail,
),
),
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPEmail,
resourceOwner: "org1",
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "factor otp sms removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
resourceOwner: "org1",
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "add factor totp, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeTOTP,
),
),
),
@@ -1679,7 +1824,7 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTP),
domain.SecondFactorTypeTOTP),
),
},
),
@@ -1687,7 +1832,77 @@ func TestCommandSide_RemoveSecondFactoroginPolicy(t *testing.T) {
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTP,
factor: domain.SecondFactorTypeTOTP,
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "add factor otp email, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPEmail,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPEmail),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPEmail,
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "add factor otp sms, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
org.NewLoginPolicySecondFactorAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
domain.SecondFactorTypeOTPSMS),
),
},
),
),
},
args: args{
ctx: context.Background(),
factor: domain.SecondFactorTypeOTPSMS,
resourceOwner: "org1",
},
res: res{