From a60029121667c9015693fc24c217a7a2dcfcdecf Mon Sep 17 00:00:00 2001 From: YutaNakagawa Date: Mon, 17 Jul 2023 11:34:46 +0900 Subject: [PATCH 1/2] Add MultiplefactorConfig.state support in Project and Tenant config --- auth/multi_factor_config_mgt.go | 10 ++++++++-- auth/multi_factor_config_mgt_test.go | 18 +++++++++++++++--- auth/project_config_mgt_test.go | 3 +++ auth/tenant_mgt_test.go | 6 ++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/auth/multi_factor_config_mgt.go b/auth/multi_factor_config_mgt.go index d01e2f46..d0aa77fd 100644 --- a/auth/multi_factor_config_mgt.go +++ b/auth/multi_factor_config_mgt.go @@ -45,6 +45,8 @@ const ( // MultiFactorConfig represents a multi-factor configuration for a tenant or project. // This can be used to define whether multi-factor authentication is enabled or disabled and the list of second factor challenges that are supported. type MultiFactorConfig struct { + // The multi-factor config state. + State MultiFactorConfigState `json:"state,omitempty"` // A slice of pointers to ProviderConfig structs, each outlining the specific second factor authorization method. ProviderConfigs []*ProviderConfig `json:"providerConfigs,omitempty"` } @@ -53,8 +55,12 @@ func (mfa *MultiFactorConfig) validate() error { if mfa == nil { return nil } - if len(mfa.ProviderConfigs) == 0 { - return fmt.Errorf("\"ProviderConfigs\" must be a non-empty array of type \"ProviderConfig\"s") + if mfa.State == "" && len(mfa.ProviderConfigs) == 0 { + return fmt.Errorf("\"State\" or \"ProviderConfigs\" must be a non-empty") + } + state := string(mfa.State) + if state != "" && state != string(Enabled) && state != string(Disabled) { + return fmt.Errorf("\"MultiFactorConfig.State\" must be 'Enabled' or 'Disabled'") } for _, providerConfig := range mfa.ProviderConfigs { if providerConfig == nil { diff --git a/auth/multi_factor_config_mgt_test.go b/auth/multi_factor_config_mgt_test.go index ebbef4eb..3dcfeee0 100644 --- a/auth/multi_factor_config_mgt_test.go +++ b/auth/multi_factor_config_mgt_test.go @@ -20,6 +20,7 @@ import ( func TestMultiFactorConfig(t *testing.T) { mfa := MultiFactorConfig{ + State: Enabled, ProviderConfigs: []*ProviderConfig{{ State: Disabled, TOTPProviderConfig: &TOTPProviderConfig{ @@ -31,9 +32,20 @@ func TestMultiFactorConfig(t *testing.T) { t.Errorf("MultiFactorConfig not valid") } } -func TestMultiFactorConfigNoProviderConfigs(t *testing.T) { + +func TestMultiFactorConfigNoStateNoProviderConfigs(t *testing.T) { mfa := MultiFactorConfig{} - want := "\"ProviderConfigs\" must be a non-empty array of type \"ProviderConfig\"s" + want := "\"State\" or \"ProviderConfigs\" must be a non-empty" + if err := mfa.validate(); err.Error() != want { + t.Errorf("MultiFactorConfig.validate(nil) = %v, want = %q", err, want) + } +} + +func TestMultiFactorConfigInvalidState(t *testing.T) { + mfa := MultiFactorConfig{ + State: "invalid", + } + want := "\"MultiFactorConfig.State\" must be 'Enabled' or 'Disabled'" if err := mfa.validate(); err.Error() != want { t.Errorf("MultiFactorConfig.validate(nil) = %v, want = %q", err, want) } @@ -43,7 +55,7 @@ func TestMultiFactorConfigNilProviderConfigs(t *testing.T) { mfa := MultiFactorConfig{ ProviderConfigs: nil, } - want := "\"ProviderConfigs\" must be a non-empty array of type \"ProviderConfig\"s" + want := "\"State\" or \"ProviderConfigs\" must be a non-empty" if err := mfa.validate(); err.Error() != want { t.Errorf("MultiFactorConfig.validate(nil) = %v, want = %q", err, want) } diff --git a/auth/project_config_mgt_test.go b/auth/project_config_mgt_test.go index ec0fa756..d5c4f8a6 100644 --- a/auth/project_config_mgt_test.go +++ b/auth/project_config_mgt_test.go @@ -28,6 +28,7 @@ import ( const projectConfigResponse = `{ "mfa": { + "state":"ENABLED", "providerConfigs": [ { "state":"ENABLED", @@ -41,6 +42,7 @@ const projectConfigResponse = `{ var testProjectConfig = &ProjectConfig{ MultiFactorConfig: &MultiFactorConfig{ + State: Enabled, ProviderConfigs: []*ProviderConfig{ { State: Enabled, @@ -84,6 +86,7 @@ func TestUpdateProjectConfig(t *testing.T) { } wantBody := map[string]interface{}{ "mfa": map[string]interface{}{ + "state": "ENABLED", "providerConfigs": []interface{}{ map[string]interface{}{ "state": "ENABLED", diff --git a/auth/tenant_mgt_test.go b/auth/tenant_mgt_test.go index 77c26851..decd6232 100644 --- a/auth/tenant_mgt_test.go +++ b/auth/tenant_mgt_test.go @@ -1087,6 +1087,7 @@ const tenantResponse = `{ "enableEmailLinkSignin": true, "enableAnonymousUser": true, "mfaConfig": { + "state": "ENABLED", "providerConfigs": [ { "state":"ENABLED", @@ -1105,6 +1106,7 @@ const tenantResponse2 = `{ "enableEmailLinkSignin": true, "enableAnonymousUser": true, "mfaConfig": { + "state": "ENABLED", "providerConfigs": [ { "state":"ENABLED", @@ -1129,6 +1131,7 @@ var testTenant = &Tenant{ EnableEmailLinkSignIn: true, EnableAnonymousUsers: true, MultiFactorConfig: &MultiFactorConfig{ + State: Enabled, ProviderConfigs: []*ProviderConfig{ { State: Enabled, @@ -1147,6 +1150,7 @@ var testTenant2 = &Tenant{ EnableEmailLinkSignIn: true, EnableAnonymousUsers: true, MultiFactorConfig: &MultiFactorConfig{ + State: Enabled, ProviderConfigs: []*ProviderConfig{ { State: Enabled, @@ -1239,6 +1243,7 @@ func TestCreateTenant(t *testing.T) { "enableEmailLinkSignin": testTenant.EnableEmailLinkSignIn, "enableAnonymousUser": testTenant.EnableAnonymousUsers, "mfaConfig": map[string]interface{}{ + "state": "ENABLED", "providerConfigs": []interface{}{ map[string]interface{}{ "state": "ENABLED", @@ -1351,6 +1356,7 @@ func TestUpdateTenant(t *testing.T) { "enableEmailLinkSignin": testTenant.EnableEmailLinkSignIn, "enableAnonymousUser": testTenant.EnableAnonymousUsers, "mfaConfig": map[string]interface{}{ + "state": "ENABLED", "providerConfigs": []interface{}{ map[string]interface{}{ "state": "ENABLED", From 4575aff84bfe2314e0111ee0ef8b7d7da52df12f Mon Sep 17 00:00:00 2001 From: YutaNakagawa Date: Mon, 17 Jul 2023 15:14:32 +0900 Subject: [PATCH 2/2] Add integration test for MFA settings --- integration/auth/project_config_mgt_test.go | 2 + integration/auth/tenant_mgt_test.go | 60 ++++++++++++--------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/integration/auth/project_config_mgt_test.go b/integration/auth/project_config_mgt_test.go index 50284005..7beb0591 100644 --- a/integration/auth/project_config_mgt_test.go +++ b/integration/auth/project_config_mgt_test.go @@ -23,6 +23,7 @@ import ( func TestProjectConfig(t *testing.T) { mfaObject := &auth.MultiFactorConfig{ + State: auth.Enabled, ProviderConfigs: []*auth.ProviderConfig{ { State: auth.Enabled, @@ -35,6 +36,7 @@ func TestProjectConfig(t *testing.T) { want := &auth.ProjectConfig{ MultiFactorConfig: mfaObject, } + t.Run("UpdateProjectConfig()", func(t *testing.T) { mfaConfigReq := *want.MultiFactorConfig req := (&auth.ProjectConfigToUpdate{}). diff --git a/integration/auth/tenant_mgt_test.go b/integration/auth/tenant_mgt_test.go index 8682cb33..e2534f2f 100644 --- a/integration/auth/tenant_mgt_test.go +++ b/integration/auth/tenant_mgt_test.go @@ -138,37 +138,45 @@ func TestTenantManager(t *testing.T) { }) t.Run("UpdateTenant()", func(t *testing.T) { - mfaObject := &auth.MultiFactorConfig{ - ProviderConfigs: []*auth.ProviderConfig{ - { - State: auth.Enabled, - TOTPProviderConfig: &auth.TOTPProviderConfig{ - AdjacentIntervals: 5, + mfaObjects := []*auth.MultiFactorConfig{ + &auth.MultiFactorConfig{ + State: auth.Enabled, + }, + &auth.MultiFactorConfig{ + ProviderConfigs: []*auth.ProviderConfig{ + { + State: auth.Enabled, + TOTPProviderConfig: &auth.TOTPProviderConfig{ + AdjacentIntervals: 5, + }, }, }, }, } - want = &auth.Tenant{ - ID: id, - DisplayName: "updated-go-tenant", - AllowPasswordSignUp: false, - EnableEmailLinkSignIn: false, - EnableAnonymousUsers: false, - MultiFactorConfig: mfaObject, - } - req := (&auth.TenantToUpdate{}). - DisplayName("updated-go-tenant"). - AllowPasswordSignUp(false). - EnableEmailLinkSignIn(false). - EnableAnonymousUsers(false). - MultiFactorConfig(*mfaObject) - tenant, err := client.TenantManager.UpdateTenant(context.Background(), id, req) - if err != nil { - t.Fatalf("UpdateTenant() = %v", err) - } - if !reflect.DeepEqual(tenant, want) { - t.Errorf("UpdateTenant() = %#v; want = %#v", tenant, want) + for _, mfaObject := range mfaObjects { + want = &auth.Tenant{ + ID: id, + DisplayName: "updated-go-tenant", + AllowPasswordSignUp: false, + EnableEmailLinkSignIn: false, + EnableAnonymousUsers: false, + MultiFactorConfig: mfaObject, + } + req := (&auth.TenantToUpdate{}). + DisplayName("updated-go-tenant"). + AllowPasswordSignUp(false). + EnableEmailLinkSignIn(false). + EnableAnonymousUsers(false). + MultiFactorConfig(*mfaObject) + tenant, err := client.TenantManager.UpdateTenant(context.Background(), id, req) + if err != nil { + t.Fatalf("UpdateTenant() = %v", err) + } + + if !reflect.DeepEqual(tenant, want) { + t.Errorf("UpdateTenant() = %#v; want = %#v", tenant, want) + } } })