From 41e8bfb61cb1dd06ca1417d0be3fb4dd6710ee7b Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Sun, 26 Jul 2020 11:10:36 +0200 Subject: [PATCH 1/6] correctly transfer username validation to auth0 closes https://github.com/alexkappa/terraform-provider-auth0/issues/238 --- auth0/resource_auth0_connection.go | 34 ++++++++++++++++++++----- auth0/resource_auth0_connection_test.go | 12 +++++++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/auth0/resource_auth0_connection.go b/auth0/resource_auth0_connection.go index 94e5f81e..9aa11f7f 100644 --- a/auth0/resource_auth0_connection.go +++ b/auth0/resource_auth0_connection.go @@ -81,8 +81,33 @@ var connectionSchema = map[string]*schema.Schema{ Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "validation": { - Type: schema.TypeMap, - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeMap, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "requires_username": { + Type: schema.TypeBool, + Optional: true, + }, + "username": { + Optional: true, + Type: schema.TypeMap, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "min": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + }, + }, Optional: true, }, "password_policy": { @@ -180,11 +205,6 @@ var connectionSchema = map[string]*schema.Schema{ Optional: true, Description: "Indicates whether or not to allow user sign-ups to your application", }, - "requires_username": { - Type: schema.TypeBool, - Optional: true, - Description: "Indicates whether or not the user is required to provide a username in addition to an email address", - }, "custom_scripts": { Type: schema.TypeMap, Elem: &schema.Schema{Type: schema.TypeString}, diff --git a/auth0/resource_auth0_connection_test.go b/auth0/resource_auth0_connection_test.go index b17c6200..4c5b6239 100644 --- a/auth0/resource_auth0_connection_test.go +++ b/auth0/resource_auth0_connection_test.go @@ -73,7 +73,9 @@ func TestAccConnection(t *testing.T) { resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.brute_force_protection", "true"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.import_mode", "false"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.disable_signup", "false"), - resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.requires_username", "true"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.requires_username", "true"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.username.min", "10"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.username.min", "40"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.custom_scripts.get_user", "myFunction"), resource.TestCheckResourceAttrSet("auth0_connection.my_connection", "options.0.configuration.foo"), ), @@ -110,11 +112,17 @@ resource "auth0_connection" "my_connection" { password_complexity_options { min_length = 6 } + validation { + requires_username = true + username = { + min = 10 + max = 40 + } + } enabled_database_customization = false brute_force_protection = true import_mode = false disable_signup = false - requires_username = true custom_scripts = { get_user = "myFunction" } From 1cf2d1f65af9c9ee3c9c78fa3fc66237c092d570 Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Wed, 29 Jul 2020 00:42:14 +0200 Subject: [PATCH 2/6] add mapping for validation options --- auth0/structure_auth0_connection.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/auth0/structure_auth0_connection.go b/auth0/structure_auth0_connection.go index 32a38a9a..f70d6f76 100644 --- a/auth0/structure_auth0_connection.go +++ b/auth0/structure_auth0_connection.go @@ -66,7 +66,6 @@ func flattenConnectionOptionsAuth0(d ResourceData, o *management.ConnectionOptio "brute_force_protection": o.GetBruteForceProtection(), "import_mode": o.GetImportMode(), "disable_signup": o.GetDisableSignup(), - "requires_username": o.GetRequiresUsername(), "custom_scripts": o.CustomScripts, "configuration": Map(d, "configuration"), // does not get read back } @@ -291,10 +290,19 @@ func expandConnectionOptionsGitHub(d ResourceData) *management.ConnectionOptions func expandConnectionOptionsAuth0(d ResourceData) *management.ConnectionOptions { o := &management.ConnectionOptions{ - Validation: Map(d, "validation"), PasswordPolicy: String(d, "password_policy"), } + List(d, "validation").Elem(func(d ResourceData) { + o.Validation = make(map[string]interface{}) + List(d, "username").Elem(func(d ResourceData) { + usernameValidation := make(map[string]*int) + usernameValidation["min"] = Int(d, "min") + usernameValidation["max"] = Int(d, "max") + o.Validation["username"] = usernameValidation + }) + }) + List(d, "password_history").Elem(func(d ResourceData) { o.PasswordHistory = make(map[string]interface{}) o.PasswordHistory["enable"] = Bool(d, "enable") From 3a5d2f1cff1e718370ebd3587ecd4885cb809a67 Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Wed, 29 Jul 2020 00:42:34 +0200 Subject: [PATCH 3/6] correct tests and remove changes for requires_username --- auth0/resource_auth0_connection.go | 14 ++++++++------ auth0/resource_auth0_connection_test.go | 12 ++++++------ auth0/structure_auth0_connection.go | 1 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/auth0/resource_auth0_connection.go b/auth0/resource_auth0_connection.go index 9aa11f7f..b9ec631c 100644 --- a/auth0/resource_auth0_connection.go +++ b/auth0/resource_auth0_connection.go @@ -81,16 +81,14 @@ var connectionSchema = map[string]*schema.Schema{ Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "validation": { - Type: schema.TypeMap, + Type: schema.TypeList, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "requires_username": { - Type: schema.TypeBool, - Optional: true, - }, "username": { Optional: true, - Type: schema.TypeMap, + Type: schema.TypeList, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "min": { @@ -205,6 +203,10 @@ var connectionSchema = map[string]*schema.Schema{ Optional: true, Description: "Indicates whether or not to allow user sign-ups to your application", }, + "requires_username": { + Type: schema.TypeBool, + Optional: true, + }, "custom_scripts": { Type: schema.TypeMap, Elem: &schema.Schema{Type: schema.TypeString}, diff --git a/auth0/resource_auth0_connection_test.go b/auth0/resource_auth0_connection_test.go index 4c5b6239..35e27c46 100644 --- a/auth0/resource_auth0_connection_test.go +++ b/auth0/resource_auth0_connection_test.go @@ -73,9 +73,9 @@ func TestAccConnection(t *testing.T) { resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.brute_force_protection", "true"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.import_mode", "false"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.disable_signup", "false"), - resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.requires_username", "true"), - resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.username.min", "10"), - resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.username.min", "40"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.requires_username", "true"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.0.username.0.min", "10"), + resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.validation.0.username.0.max", "40"), resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.custom_scripts.get_user", "myFunction"), resource.TestCheckResourceAttrSet("auth0_connection.my_connection", "options.0.configuration.foo"), ), @@ -113,12 +113,12 @@ resource "auth0_connection" "my_connection" { min_length = 6 } validation { - requires_username = true - username = { + username { min = 10 max = 40 } } + requires_username = true enabled_database_customization = false brute_force_protection = true import_mode = false @@ -148,11 +148,11 @@ resource "auth0_connection" "my_connection" { password_no_personal_info { enable = true } + requires_username = true enabled_database_customization = false brute_force_protection = false import_mode = false disable_signup = false - requires_username = true custom_scripts = { get_user = "myFunction" } diff --git a/auth0/structure_auth0_connection.go b/auth0/structure_auth0_connection.go index f70d6f76..34c124e9 100644 --- a/auth0/structure_auth0_connection.go +++ b/auth0/structure_auth0_connection.go @@ -66,6 +66,7 @@ func flattenConnectionOptionsAuth0(d ResourceData, o *management.ConnectionOptio "brute_force_protection": o.GetBruteForceProtection(), "import_mode": o.GetImportMode(), "disable_signup": o.GetDisableSignup(), + "requires_username": o.GetRequiresUsername(), "custom_scripts": o.CustomScripts, "configuration": Map(d, "configuration"), // does not get read back } From fbbe2b1beeb196df11d2b904968bbff4919ca706 Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Wed, 26 Aug 2020 18:38:34 +0200 Subject: [PATCH 4/6] reset unrelated diff --- auth0/resource_auth0_connection.go | 1 + auth0/resource_auth0_connection_test.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/auth0/resource_auth0_connection.go b/auth0/resource_auth0_connection.go index b9ec631c..ffb0e6d1 100644 --- a/auth0/resource_auth0_connection.go +++ b/auth0/resource_auth0_connection.go @@ -206,6 +206,7 @@ var connectionSchema = map[string]*schema.Schema{ "requires_username": { Type: schema.TypeBool, Optional: true, + Description: "Indicates whether or not the user is required to provide a username in addition to an email address", }, "custom_scripts": { Type: schema.TypeMap, diff --git a/auth0/resource_auth0_connection_test.go b/auth0/resource_auth0_connection_test.go index 35e27c46..078e2326 100644 --- a/auth0/resource_auth0_connection_test.go +++ b/auth0/resource_auth0_connection_test.go @@ -118,10 +118,10 @@ resource "auth0_connection" "my_connection" { max = 40 } } - requires_username = true enabled_database_customization = false brute_force_protection = true import_mode = false + requires_username = true disable_signup = false custom_scripts = { get_user = "myFunction" @@ -148,11 +148,11 @@ resource "auth0_connection" "my_connection" { password_no_personal_info { enable = true } - requires_username = true enabled_database_customization = false brute_force_protection = false import_mode = false disable_signup = false + requires_username = true custom_scripts = { get_user = "myFunction" } From 84f9725a34390132aacf6108606a8890571f9845 Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Sat, 5 Sep 2020 09:58:18 +0200 Subject: [PATCH 5/6] migrate validation map to validation.username --- auth0/resource_auth0_connection.go | 37 ++++++++++++++- auth0/resource_auth0_connection_test.go | 62 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/auth0/resource_auth0_connection.go b/auth0/resource_auth0_connection.go index ffb0e6d1..fa2896a4 100644 --- a/auth0/resource_auth0_connection.go +++ b/auth0/resource_auth0_connection.go @@ -204,8 +204,8 @@ var connectionSchema = map[string]*schema.Schema{ Description: "Indicates whether or not to allow user sign-ups to your application", }, "requires_username": { - Type: schema.TypeBool, - Optional: true, + Type: schema.TypeBool, + Optional: true, Description: "Indicates whether or not the user is required to provide a username in addition to an email address", }, "custom_scripts": { @@ -591,6 +591,39 @@ func connectionSchemaUpgradeV0(state map[string]interface{}, meta interface{}) ( return state, nil } +func connectionSchemaUpgradeV1(state map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + + o, ok := state["options"] + if !ok { + return state, nil + } + + l, ok := o.([]interface{}) + if ok && len(l) > 0 { + + m := l[0].(map[string]interface{}) + + v, ok := m["validation"] + if !ok { + return state, nil + } + + validation := v.(interface{}) + + m["validation"] = []map[string]interface{}{ + { + "username": validation, + }, + } + + state["options"] = []interface{}{m} + + log.Print("[DEBUG] Schema upgrade: options.validation has been migrated to options.validation.user") + } + + return state, nil +} + func createConnection(d *schema.ResourceData, m interface{}) error { c := expandConnection(d) api := m.(*management.Management) diff --git a/auth0/resource_auth0_connection_test.go b/auth0/resource_auth0_connection_test.go index 078e2326..976a3ff1 100644 --- a/auth0/resource_auth0_connection_test.go +++ b/auth0/resource_auth0_connection_test.go @@ -1010,6 +1010,68 @@ func TestConnectionInstanceStateUpgradeV0(t *testing.T) { } } +func TestConnectionInstanceStateUpgradeV1(t *testing.T) { + + for _, tt := range []struct { + name string + validation map[string]string + validationExpected []map[string]interface{} + }{ + { + name: "Only Min", + validation: map[string]string{ + "min": "5", + }, + validationExpected: []map[string]interface{}{ + { + "username": map[string]string{ + "min": "5", + }, + }, + }, + }, + { + name: "Min and Max", + validation: map[string]string{ + "min": "5", + "max": "10", + }, + validationExpected: []map[string]interface{}{ + { + "username": map[string]string{ + "min": "5", + "max": "10", + }, + }, + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + + state := map[string]interface{}{ + "options": []interface{}{ + map[string]interface{}{"validation": tt.validation}, + }, + } + + actual, err := connectionSchemaUpgradeV1(state, nil) + if err != nil { + t.Fatalf("error migrating state: %s", err) + } + + expected := map[string]interface{}{ + "options": []interface{}{ + map[string]interface{}{"validation": tt.validationExpected}, + }, + } + + if !reflect.DeepEqual(expected, actual) { + t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual) + } + }) + } +} + func TestAccConnectionSAML(t *testing.T) { rand := random.String(6) From 9ea0ee636b259808476b2c9bf31577934e508145 Mon Sep 17 00:00:00 2001 From: etwillbefine Date: Sat, 5 Sep 2020 11:31:04 +0200 Subject: [PATCH 6/6] username is a list of maps --- auth0/resource_auth0_connection.go | 4 ++-- auth0/resource_auth0_connection_test.go | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/auth0/resource_auth0_connection.go b/auth0/resource_auth0_connection.go index fa2896a4..1d21de3a 100644 --- a/auth0/resource_auth0_connection.go +++ b/auth0/resource_auth0_connection.go @@ -610,9 +610,9 @@ func connectionSchemaUpgradeV1(state map[string]interface{}, meta interface{}) ( validation := v.(interface{}) - m["validation"] = []map[string]interface{}{ + m["validation"] = []map[string][]interface{}{ { - "username": validation, + "username": []interface{}{validation}, }, } diff --git a/auth0/resource_auth0_connection_test.go b/auth0/resource_auth0_connection_test.go index 976a3ff1..1283b061 100644 --- a/auth0/resource_auth0_connection_test.go +++ b/auth0/resource_auth0_connection_test.go @@ -1015,17 +1015,19 @@ func TestConnectionInstanceStateUpgradeV1(t *testing.T) { for _, tt := range []struct { name string validation map[string]string - validationExpected []map[string]interface{} + validationExpected []map[string][]interface{} }{ { name: "Only Min", validation: map[string]string{ "min": "5", }, - validationExpected: []map[string]interface{}{ + validationExpected: []map[string][]interface{}{ { - "username": map[string]string{ - "min": "5", + "username": []interface{}{ + map[string]string{ + "min": "5", + }, }, }, }, @@ -1034,13 +1036,15 @@ func TestConnectionInstanceStateUpgradeV1(t *testing.T) { name: "Min and Max", validation: map[string]string{ "min": "5", - "max": "10", + "max": "5", }, - validationExpected: []map[string]interface{}{ + validationExpected: []map[string][]interface{}{ { - "username": map[string]string{ - "min": "5", - "max": "10", + "username": []interface{}{ + map[string]string{ + "min": "5", + "max": "10", + }, }, }, }, @@ -1050,7 +1054,7 @@ func TestConnectionInstanceStateUpgradeV1(t *testing.T) { state := map[string]interface{}{ "options": []interface{}{ - map[string]interface{}{"validation": tt.validation}, + map[string][]interface{}{"validation": []interface{}{tt.validation}}, }, }