diff --git a/auth0/resource_auth0_attack_protection.go b/auth0/resource_auth0_attack_protection.go index ca1001cfb..ea2ce4501 100644 --- a/auth0/resource_auth0_attack_protection.go +++ b/auth0/resource_auth0_attack_protection.go @@ -1,7 +1,6 @@ package auth0 import ( - "fmt" "net/http" "github.com/auth0/go-auth0/management" @@ -208,6 +207,11 @@ func newAttackProtection() *schema.Resource { } } +func createAttackProtection(d *schema.ResourceData, m interface{}) error { + d.SetId(resource.UniqueId()) + return updateAttackProtection(d, m) +} + func readAttackProtection(d *schema.ResourceData, m interface{}) error { api := m.(*management.Management) @@ -259,24 +263,61 @@ func readAttackProtection(d *schema.ResourceData, m interface{}) error { return nil } +func updateAttackProtection(d *schema.ResourceData, m interface{}) error { + api := m.(*management.Management) + + if ipt := expandSuspiciousIPThrottling(d); ipt != nil { + if err := api.AttackProtection.UpdateSuspiciousIPThrottling(ipt); err != nil { + return err + } + } + + if bfp := expandBruteForceProtection(d); bfp != nil { + if err := api.AttackProtection.UpdateBruteForceProtection(bfp); err != nil { + return err + } + } + + if bpd := expandBreachedPasswordDetection(d); bpd != nil { + if err := api.AttackProtection.UpdateBreachedPasswordDetection(bpd); err != nil { + return err + } + } + + return readAttackProtection(d, m) +} + +func deleteAttackProtection(d *schema.ResourceData, m interface{}) error { + d.SetId("") + return nil +} + func flattenSuspiciousIPThrottling(ipt *management.SuspiciousIPThrottling) []interface{} { m := make(map[string]interface{}) if ipt != nil { m["enabled"] = ipt.Enabled m["allowlist"] = ipt.AllowList m["shields"] = ipt.Shields - m["pre_login"] = []interface{}{ - map[string]int{ - "max_attempts": ipt.Stage.PreLogin.GetMaxAttempts(), - "rate": ipt.Stage.PreLogin.GetRate(), - }, - } - m["pre_user_registration"] = []interface{}{ - map[string]int{ - "max_attempts": ipt.Stage.PreUserRegistration.GetMaxAttempts(), - "rate": ipt.Stage.PreUserRegistration.GetRate(), - }, + + if ipt.Stage != nil { + if ipt.Stage.PreLogin != nil { + m["pre_login"] = []interface{}{ + map[string]int{ + "max_attempts": ipt.Stage.PreLogin.GetMaxAttempts(), + "rate": ipt.Stage.PreLogin.GetRate(), + }, + } + } + if ipt.Stage.PreUserRegistration != nil { + m["pre_user_registration"] = []interface{}{ + map[string]int{ + "max_attempts": ipt.Stage.PreUserRegistration.GetMaxAttempts(), + "rate": ipt.Stage.PreUserRegistration.GetRate(), + }, + } + } } + } return []interface{}{m} } @@ -304,125 +345,103 @@ func flattenBreachedPasswordProtection(bpd *management.BreachedPasswordDetection return []interface{}{m} } -func updateAttackProtection(d *schema.ResourceData, m interface{}) error { - api := m.(*management.Management) - - ipt := expandSuspiciousIPThrottling(d) - err := api.AttackProtection.UpdateSuspiciousIPThrottling(ipt) - if err != nil { - return err - } - - bfp := expandBruteForceProtection(d) - err = api.AttackProtection.UpdateBruteForceProtection(bfp) - if err != nil { - return err - } - - bpd := expandBreachedPasswordDetection(d) - err = api.AttackProtection.UpdateBreachedPasswordDetection(bpd) - if err != nil { - return err - } - - return readAttackProtection(d, m) -} - func expandSuspiciousIPThrottling(d *schema.ResourceData) *management.SuspiciousIPThrottling { - ipt := &management.SuspiciousIPThrottling{} + var ipt management.SuspiciousIPThrottling List(d, "suspicious_ip_throttling", IsNewResource(), HasChange()).Elem(func(d ResourceData) { - shields := []string{} - for _, s := range d.Get("shields").([]interface{}) { - shields = append(shields, fmt.Sprintf("%s", s)) - } + ipt.Enabled = Bool(d, "enabled") - allowlist := []string{} - for _, a := range d.Get("allowlist").([]interface{}) { - allowlist = append(allowlist, fmt.Sprintf("%s", a)) + stateShields := d.Get("shields").([]interface{}) + shields := make([]string, len(stateShields)) + for index, value := range stateShields { + shields[index] = value.(string) } + ipt.Shields = &shields - ipt = &management.SuspiciousIPThrottling{ - Enabled: Bool(d, "enabled"), - Shields: &shields, - AllowList: &allowlist, - Stage: &management.Stage{ - PreLogin: &management.PreLogin{}, - PreUserRegistration: &management.PreUserRegistration{}, - }, + stateAllowList := d.Get("allowlist").([]interface{}) + allowlist := make([]string, len(stateAllowList)) + for index, value := range stateAllowList { + allowlist[index] = value.(string) } + ipt.AllowList = &allowlist - List(d, "pre_login").Elem(func(d ResourceData) { - ipt.Stage.PreLogin.MaxAttempts = Int(d, "max_attempts") - ipt.Stage.PreLogin.Rate = Int(d, "rate") + List(d, "pre_login", IsNewResource(), HasChange()).Elem(func(d ResourceData) { + ipt.Stage = &management.Stage{ + PreLogin: &management.PreLogin{ + MaxAttempts: Int(d, "max_attempts"), + Rate: Int(d, "rate"), + }, + } }) - List(d, "pre_user_registration").Elem(func(d ResourceData) { - ipt.Stage.PreUserRegistration.MaxAttempts = Int(d, "max_attempts") - ipt.Stage.PreUserRegistration.Rate = Int(d, "rate") + List(d, "pre_user_registration", IsNewResource(), HasChange()).Elem(func(d ResourceData) { + preUserRegistration := &management.PreUserRegistration{ + MaxAttempts: Int(d, "max_attempts"), + Rate: Int(d, "rate"), + } + + if ipt.Stage != nil { + ipt.Stage.PreUserRegistration = preUserRegistration + } else { + ipt.Stage = &management.Stage{ + PreUserRegistration: preUserRegistration, + } + } }) }) - return ipt + return &ipt } func expandBruteForceProtection(d *schema.ResourceData) *management.BruteForceProtection { - bfp := &management.BruteForceProtection{} + var bfp management.BruteForceProtection List(d, "brute_force_protection", IsNewResource(), HasChange()).Elem(func(d ResourceData) { - shields := []string{} - for _, s := range d.Get("shields").([]interface{}) { - shields = append(shields, fmt.Sprintf("%s", s)) - } + bfp.Enabled = Bool(d, "enabled") - allowlist := []string{} - for _, a := range d.Get("allowlist").([]interface{}) { - allowlist = append(allowlist, fmt.Sprintf("%s", a)) + stateShields := d.Get("shields").([]interface{}) + shields := make([]string, len(stateShields)) + for index, value := range stateShields { + shields[index] = value.(string) } + bfp.Shields = &shields - bfp = &management.BruteForceProtection{ - Enabled: Bool(d, "enabled"), - Shields: &shields, - AllowList: &allowlist, - Mode: String(d, "mode"), - MaxAttempts: Int(d, "max_attempts"), + stateAllowList := d.Get("allowlist").([]interface{}) + allowlist := make([]string, len(stateAllowList)) + for index, value := range stateAllowList { + allowlist[index] = value.(string) } + bfp.AllowList = &allowlist + + bfp.Mode = String(d, "mode") + bfp.MaxAttempts = Int(d, "max_attempts") }) - return bfp + return &bfp } func expandBreachedPasswordDetection(d *schema.ResourceData) *management.BreachedPasswordDetection { - bpd := &management.BreachedPasswordDetection{} + var bpd management.BreachedPasswordDetection List(d, "breached_password_detection", IsNewResource(), HasChange()).Elem(func(d ResourceData) { - shields := []string{} - for _, s := range d.Get("shields").([]interface{}) { - shields = append(shields, fmt.Sprintf("%s", s)) - } + bpd.Enabled = Bool(d, "enabled") - notificationFreq := []string{} - for _, a := range d.Get("admin_notification_frequency").([]interface{}) { - notificationFreq = append(notificationFreq, fmt.Sprintf("%s", a)) + stateShields := d.Get("shields").([]interface{}) + shields := make([]string, len(stateShields)) + for index, value := range stateShields { + shields[index] = value.(string) } + bpd.Shields = &shields - bpd = &management.BreachedPasswordDetection{ - Enabled: Bool(d, "enabled"), - Shields: &shields, - Method: String(d, "method"), - AdminNotificationFrequency: ¬ificationFreq, + stateAdminNotificationFrequency := d.Get("admin_notification_frequency").([]interface{}) + adminNotificationFrequency := make([]string, len(stateAdminNotificationFrequency)) + for index, value := range stateAdminNotificationFrequency { + adminNotificationFrequency[index] = value.(string) } - }) - - return bpd -} + bpd.AdminNotificationFrequency = &adminNotificationFrequency -func createAttackProtection(d *schema.ResourceData, m interface{}) error { - d.SetId(resource.UniqueId()) - return updateAttackProtection(d, m) -} + bpd.Method = String(d, "method") + }) -func deleteAttackProtection(d *schema.ResourceData, m interface{}) error { - d.SetId("") - return nil + return &bpd } diff --git a/auth0/resource_auth0_attack_protection_test.go b/auth0/resource_auth0_attack_protection_test.go index 135378440..b2ed1b3f6 100644 --- a/auth0/resource_auth0_attack_protection_test.go +++ b/auth0/resource_auth0_attack_protection_test.go @@ -8,7 +8,6 @@ import ( ) func TestAccAttackProtection(t *testing.T) { - resource.Test(t, resource.TestCase{ Providers: map[string]terraform.ResourceProvider{ "auth0": Provider(), diff --git a/docs/resources/attack_protection.md b/docs/resources/attack_protection.md index 678ce8483..5518e5833 100644 --- a/docs/resources/attack_protection.md +++ b/docs/resources/attack_protection.md @@ -58,7 +58,7 @@ The following arguments are supported for `brute_force_protection`: * `shields` - (Optional) Action to take when a brute force protection threshold is violated. Possible values: `block`, `user_notification`. * `allowlist` - (Optional) List of trusted IP addresses that will not have attack protection enforced against them. * `mode` - (Optional) Determines whether or not IP address is used when counting failed attempts. Possible values: `count_per_identifier_and_ip` or `count_per_identifier`. -* `max_attempts` - (Optional) Maximum number of unsuccessful attempts. +* `max_attempts` - (Optional) Maximum number of unsuccessful attempts. Only available on public tenants. ### suspicious_ip_throttling @@ -67,8 +67,8 @@ The following arguments are supported for `suspicious_ip_throttling`: * `enabled` - (Optional) Whether or not suspicious IP throttling attack protections are active. * `shields` - (Optional) Action to take when a suspicious IP throttling threshold is violated. Possible values: `block`, `admin_notification`. * `allowlist` - (Optional) List of trusted IP addresses that will not have attack protection enforced against them. -* `pre_login` - (Optional) Configuration options that apply before every login attempt. -* `pre_user_registration` - (Optional) Configuration options that apply before every user registration attempt. +* `pre_login` - (Optional) Configuration options that apply before every login attempt. Only available on public tenants. +* `pre_user_registration` - (Optional) Configuration options that apply before every user registration attempt. Only available on public tenants. ### breached_password_protection @@ -85,4 +85,4 @@ string. We recommend [Version 4 UUID](https://www.uuidgenerator.net/version4) e. ```shell $ terraform import auth0_guardian.default 24940d4b-4bd4-44e7-894e-f92e4de36a40 -``` \ No newline at end of file +``` diff --git a/docs/resources/client.md b/docs/resources/client.md index a13995648..2cf3a3afb 100644 --- a/docs/resources/client.md +++ b/docs/resources/client.md @@ -80,6 +80,10 @@ resource "auth0_client" "my_client" { app_bundle_identifier = "com.my.bundle.id" } } + client_secret_rotation_trigger = { + triggered_at = "2018-01-02T23:12:01Z" + triggered_by = "auth0" + } } ``` @@ -89,7 +93,7 @@ Arguments accepted by this resource include: * `name` - (Required) String. Name of the client. * `description` - (Optional) String, (Max length = 140 characters). Description of the purpose of the client. -* `client_secret_rotation_trigger` - (Optional) Map. +* `client_secret_rotation_trigger` - (Optional) Map. Custom metadata for the rotation. For more info: [rotate-client-secret](https://auth0.com/docs/get-started/applications/rotate-client-secret). * `app_type` - (Optional) String. Type of application the client represents. Options include `native`, `spa`, `regular_web`, `non_interactive`, `rms`, `box`, `cloudbees`, `concur`, `dropbox`, `mscrm`, `echosign`, `egnyte`, `newrelic`, `office365`, `salesforce`, `sentry`, `sharepoint`, `slack`, `springcm`, `zendesk`, `zoom`. * `logo_uri` - (Optional) String. URL of the logo for the client. Recommended size is 150px x 150px. If none is set, the default badge for the application type will be shown. * `is_first_party` - (Optional) Boolean. Indicates whether or not this client is a first-party client.