From 5e2754b6e17c1f8ac0e6e40c8b82acfd8d1a7850 Mon Sep 17 00:00:00 2001 From: tyrjola Date: Mon, 28 Jan 2019 15:50:09 +0200 Subject: [PATCH 1/5] cognito: add support for advanced security mode --- aws/resource_aws_cognito_user_pool.go | 49 ++++++++++++++++++++++ aws/resource_aws_cognito_user_pool_test.go | 47 +++++++++++++++++++++ aws/structure.go | 14 +++++++ aws/validators.go | 12 ++++++ aws/validators_test.go | 27 ++++++++++++ website/docs/r/cognito_user_pool.markdown | 5 +++ 6 files changed, 154 insertions(+) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 33c417f1238..7839c139f91 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -412,6 +412,21 @@ func resourceAwsCognitoUserPool() *schema.Resource { ConflictsWith: []string{"alias_attributes"}, }, + "user_pool_add_ons": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "advanced_security_mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateCognitoUserPoolAdvancedSecurityMode, + }, + }, + }, + }, + "verification_message_template": { Type: schema.TypeList, Optional: true, @@ -580,6 +595,20 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) params.UsernameAttributes = expandStringList(v.([]interface{})) } + if v, ok := d.GetOk("user_pool_add_ons"); ok { + configs := v.([]interface{}) + config, ok := configs[0].(map[string]interface{}) + + if ok && config != nil { + userPoolAddons := &cognitoidentityprovider.UserPoolAddOnsType{} + + if v, ok := config["advanced_security_mode"]; ok && v.(string) != "" { + userPoolAddons.AdvancedSecurityMode = aws.String(v.(string)) + } + params.UserPoolAddOns = userPoolAddons + } + } + if v, ok := d.GetOk("verification_message_template"); ok { configs := v.([]interface{}) config, ok := configs[0].(map[string]interface{}) @@ -710,6 +739,12 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er d.Set("username_attributes", flattenStringList(resp.UserPool.UsernameAttributes)) } + if resp.UserPool.UserPoolAddOns != nil && resp.UserPool.UserPoolAddOns.AdvancedSecurityMode != nil { + if err := d.Set("user_pool_add_ons", flattenCognitoUserPoolUserPoolAddOns(resp.UserPool.UserPoolAddOns)); err != nil { + return fmt.Errorf("Failed setting user_pool_add_ons: %s", err) + } + } + if err := d.Set("verification_message_template", flattenCognitoUserPoolVerificationMessageTemplate(resp.UserPool.VerificationMessageTemplate)); err != nil { return fmt.Errorf("Failed setting verification_message_template: %s", err) } @@ -815,6 +850,20 @@ func resourceAwsCognitoUserPoolUpdate(d *schema.ResourceData, meta interface{}) } } + if v, ok := d.GetOk("user_pool_add_ons"); ok { + configs := v.([]interface{}) + config, ok := configs[0].(map[string]interface{}) + + if ok && config != nil { + userPoolAddons := &cognitoidentityprovider.UserPoolAddOnsType{} + + if v, ok := config["advanced_security_mode"]; ok && v.(string) != "" { + userPoolAddons.AdvancedSecurityMode = aws.String(v.(string)) + } + params.UserPoolAddOns = userPoolAddons + } + } + if v, ok := d.GetOk("verification_message_template"); ok { configs := v.([]interface{}) config, ok := configs[0].(map[string]interface{}) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 06992b1a552..0f612bb5f3e 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -153,6 +153,31 @@ func TestAccAWSCognitoUserPool_withAdminCreateUserConfiguration(t *testing.T) { }) } +func TestAccAWSCognitoUserPool_withAdvancedSecurityMode(t *testing.T) { + name := acctest.RandString(5) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolExists("aws_cognito_user_pool.pool"), + resource.TestCheckResourceAttr("aws_cognito_user_pool.pool", "user_pool_add_ons.0.advanced_security_mode", "OFF"), + ), + }, + { + Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityModeUpdated(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aws_cognito_user_pool.pool", "user_pool_add_ons.0.advanced_security_mode", "ENFORCED"), + ), + }, + }, + }) +} + func TestAccAWSCognitoUserPool_withDeviceConfiguration(t *testing.T) { name := acctest.RandString(5) @@ -736,6 +761,28 @@ resource "aws_cognito_user_pool" "pool" { }`, name) } +func testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "pool" { + name = "terraform-test-pool-%s" + + user_pool_add_ons { + advanced_security_mode = "OFF" + } +}`, name) +} + +func testAccAWSCognitoUserPoolConfig_withAdvancedSecurityModeUpdated(name string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "pool" { + name = "terraform-test-pool-%s" + + user_pool_add_ons { + advanced_security_mode = "ENFORCED" + } +}`, name) +} + func testAccAWSCognitoUserPoolConfig_withDeviceConfiguration(name string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "pool" { diff --git a/aws/structure.go b/aws/structure.go index 1a2449e827d..5a9c168daac 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2781,6 +2781,20 @@ func expandCognitoUserPoolPasswordPolicy(config map[string]interface{}) *cognito return configs } +func flattenCognitoUserPoolUserPoolAddOns(s *cognitoidentityprovider.UserPoolAddOnsType) []map[string]interface{} { + config := make(map[string]interface{}) + + if s == nil { + return nil + } + + if s.AdvancedSecurityMode != nil { + config["advanced_security_mode"] = *s.AdvancedSecurityMode + } + + return []map[string]interface{}{config} +} + func flattenIoTRuleCloudWatchAlarmActions(actions []*iot.Action) []map[string]interface{} { results := make([]map[string]interface{}, 0) diff --git a/aws/validators.go b/aws/validators.go index a53f0182da1..737a9e4597a 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -1544,6 +1544,18 @@ func validateCognitoUserPoolTemplateSmsMessage(v interface{}, k string) (ws []st return } +func validateCognitoUserPoolAdvancedSecurityMode(v interface{}, s string) ([]string, []error) { + switch v.(string) { + case + "OFF", + "AUDIT", + "ENFORCED": + return nil, nil + } + + return nil, []error{fmt.Errorf("Mode must be one of OFF, AUDIT, or ENFORCED")} +} + func validateCognitoUserPoolInviteTemplateEmailMessage(v interface{}, k string) (ws []string, es []error) { value := v.(string) if len(value) < 6 { diff --git a/aws/validators_test.go b/aws/validators_test.go index 02ec45c78df..4b780a4ae71 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -2163,6 +2163,33 @@ func TestValidateCognitoIdentityProvidersProviderName(t *testing.T) { } } +func TestValidateCognitoUserPoolAdvancedSecurityMode(t *testing.T) { + validValues := []string{ + "OFF", + "AUDIT", + "ENFORCED", + } + + for _, s := range validValues { + _, errors := validateCognitoUserPoolAdvancedSecurityMode(s, "advanced_security_mode") + if len(errors) > 0 { + t.Fatalf("%q should be a valid Cognito User Pool advanced security mode: %v", s, errors) + } + } + + invalidValues := []string{ + "Foo", + "Bar", + } + + for _, s := range invalidValues { + _, errors := validateCognitoUserPoolAdvancedSecurityMode(s, "advanced_security_mode") + if len(errors) == 0 { + t.Fatalf("%q should not be a valid Cognito User Pool advanced security mode: %v", s, errors) + } + } +} + func TestValidateCognitoUserPoolEmailVerificationMessage(t *testing.T) { validValues := []string{ "{####}", diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index dd48a1ca3cf..d1059778299 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -41,6 +41,7 @@ The following arguments are supported: * `sms_verification_message` - (Optional) A string representing the SMS verification message. * `tags` - (Optional) A mapping of tags to assign to the User Pool. * `username_attributes` - (Optional) Specifies whether email addresses or phone numbers can be specified as usernames when a user signs up. Conflicts with `alias_attributes`. +* `user_pool_add_ons` - (Optional) The configuration for [user pool add-ons](#user-pool-add-ons). * `verification_message_template` (Optional) - The [verification message templates](#verification-message-template) configuration. #### Admin Create User Config @@ -111,6 +112,10 @@ The following arguments are supported: * `external_id` (Required) - The external ID used in IAM role trust relationships. For more information about using external IDs, see [How to Use an External ID When Granting Access to Your AWS Resources to a Third Party](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html). * `sns_caller_arn` (Required) - The ARN of the Amazon SNS caller. This is usually the IAM role that you've given Cognito permission to assume. +#### User Pool Add-ons + + * `advanced_security_mode` (Required) - The mode for advanced security, must be one of `OFF`, `AUDIT` or `ENFORCED`. + #### Verification Message Template * `default_email_option` (Optional) - The default email option. Must be either `CONFIRM_WITH_CODE` or `CONFIRM_WITH_LINK`. Defaults to `CONFIRM_WITH_CODE`. From 48e4c8c0f7353c6562980c655bbb94446ebd689e Mon Sep 17 00:00:00 2001 From: tyrjola Date: Tue, 12 Feb 2019 14:37:33 +0200 Subject: [PATCH 2/5] cognito: refactor advanced sec mode validation --- aws/resource_aws_cognito_user_pool.go | 10 +++++++--- aws/validators.go | 12 ------------ aws/validators_test.go | 27 --------------------------- 3 files changed, 7 insertions(+), 42 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 7839c139f91..38792af1cb7 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -419,9 +419,13 @@ func resourceAwsCognitoUserPool() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "advanced_security_mode": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateCognitoUserPoolAdvancedSecurityMode, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + cognitoidentityprovider.AdvancedSecurityModeTypeAudit, + cognitoidentityprovider.AdvancedSecurityModeTypeEnforced, + cognitoidentityprovider.AdvancedSecurityModeTypeOff, + }, false), }, }, }, diff --git a/aws/validators.go b/aws/validators.go index 737a9e4597a..a53f0182da1 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -1544,18 +1544,6 @@ func validateCognitoUserPoolTemplateSmsMessage(v interface{}, k string) (ws []st return } -func validateCognitoUserPoolAdvancedSecurityMode(v interface{}, s string) ([]string, []error) { - switch v.(string) { - case - "OFF", - "AUDIT", - "ENFORCED": - return nil, nil - } - - return nil, []error{fmt.Errorf("Mode must be one of OFF, AUDIT, or ENFORCED")} -} - func validateCognitoUserPoolInviteTemplateEmailMessage(v interface{}, k string) (ws []string, es []error) { value := v.(string) if len(value) < 6 { diff --git a/aws/validators_test.go b/aws/validators_test.go index 4b780a4ae71..02ec45c78df 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -2163,33 +2163,6 @@ func TestValidateCognitoIdentityProvidersProviderName(t *testing.T) { } } -func TestValidateCognitoUserPoolAdvancedSecurityMode(t *testing.T) { - validValues := []string{ - "OFF", - "AUDIT", - "ENFORCED", - } - - for _, s := range validValues { - _, errors := validateCognitoUserPoolAdvancedSecurityMode(s, "advanced_security_mode") - if len(errors) > 0 { - t.Fatalf("%q should be a valid Cognito User Pool advanced security mode: %v", s, errors) - } - } - - invalidValues := []string{ - "Foo", - "Bar", - } - - for _, s := range invalidValues { - _, errors := validateCognitoUserPoolAdvancedSecurityMode(s, "advanced_security_mode") - if len(errors) == 0 { - t.Fatalf("%q should not be a valid Cognito User Pool advanced security mode: %v", s, errors) - } - } -} - func TestValidateCognitoUserPoolEmailVerificationMessage(t *testing.T) { validValues := []string{ "{####}", From cbcc918749b37efca6bad3e0632692336b014580 Mon Sep 17 00:00:00 2001 From: tyrjola Date: Tue, 12 Feb 2019 14:37:33 +0200 Subject: [PATCH 3/5] cognito: sanitize nil checks for user pool add-ons --- aws/resource_aws_cognito_user_pool.go | 8 +++----- aws/structure.go | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 38792af1cb7..051483a6558 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -603,7 +603,7 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) configs := v.([]interface{}) config, ok := configs[0].(map[string]interface{}) - if ok && config != nil { + if ok { userPoolAddons := &cognitoidentityprovider.UserPoolAddOnsType{} if v, ok := config["advanced_security_mode"]; ok && v.(string) != "" { @@ -743,10 +743,8 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er d.Set("username_attributes", flattenStringList(resp.UserPool.UsernameAttributes)) } - if resp.UserPool.UserPoolAddOns != nil && resp.UserPool.UserPoolAddOns.AdvancedSecurityMode != nil { - if err := d.Set("user_pool_add_ons", flattenCognitoUserPoolUserPoolAddOns(resp.UserPool.UserPoolAddOns)); err != nil { - return fmt.Errorf("Failed setting user_pool_add_ons: %s", err) - } + if err := d.Set("user_pool_add_ons", flattenCognitoUserPoolUserPoolAddOns(resp.UserPool.UserPoolAddOns)); err != nil { + return fmt.Errorf("Failed setting user_pool_add_ons: %s", err) } if err := d.Set("verification_message_template", flattenCognitoUserPoolVerificationMessageTemplate(resp.UserPool.VerificationMessageTemplate)); err != nil { diff --git a/aws/structure.go b/aws/structure.go index 5a9c168daac..d8a57fe05c6 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2785,7 +2785,7 @@ func flattenCognitoUserPoolUserPoolAddOns(s *cognitoidentityprovider.UserPoolAdd config := make(map[string]interface{}) if s == nil { - return nil + return []map[string]interface{}{} } if s.AdvancedSecurityMode != nil { From e165d0773120457b089187c28e30d819d7ee5400 Mon Sep 17 00:00:00 2001 From: tyrjola Date: Tue, 12 Feb 2019 14:37:33 +0200 Subject: [PATCH 4/5] cognito: refactor user pool add-on tests --- aws/resource_aws_cognito_user_pool_test.go | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 0f612bb5f3e..b95c29ec61d 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -162,18 +162,24 @@ func TestAccAWSCognitoUserPool_withAdvancedSecurityMode(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name), + Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name, "OFF"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolExists("aws_cognito_user_pool.pool"), resource.TestCheckResourceAttr("aws_cognito_user_pool.pool", "user_pool_add_ons.0.advanced_security_mode", "OFF"), ), }, { - Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityModeUpdated(name), + Config: testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name, "ENFORCED"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("aws_cognito_user_pool.pool", "user_pool_add_ons.0.advanced_security_mode", "ENFORCED"), ), }, + { + Config: testAccAWSCognitoUserPoolConfig_basic(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aws_cognito_user_pool.pool", "user_pool_add_ons.#", "0"), + ), + }, }, }) } @@ -761,26 +767,15 @@ resource "aws_cognito_user_pool" "pool" { }`, name) } -func testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name string) string { +func testAccAWSCognitoUserPoolConfig_withAdvancedSecurityMode(name string, mode string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "pool" { name = "terraform-test-pool-%s" user_pool_add_ons { - advanced_security_mode = "OFF" + advanced_security_mode = "%s" } -}`, name) -} - -func testAccAWSCognitoUserPoolConfig_withAdvancedSecurityModeUpdated(name string) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "pool" { - name = "terraform-test-pool-%s" - - user_pool_add_ons { - advanced_security_mode = "ENFORCED" - } -}`, name) +}`, name, mode) } func testAccAWSCognitoUserPoolConfig_withDeviceConfiguration(name string) string { From 6501c508caac52b20ebb03d7fa16cc693a1f25c0 Mon Sep 17 00:00:00 2001 From: tyrjola Date: Tue, 12 Feb 2019 14:37:33 +0200 Subject: [PATCH 5/5] docs: update user pool add-ons description --- website/docs/r/cognito_user_pool.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index d1059778299..5a45074a024 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -41,7 +41,7 @@ The following arguments are supported: * `sms_verification_message` - (Optional) A string representing the SMS verification message. * `tags` - (Optional) A mapping of tags to assign to the User Pool. * `username_attributes` - (Optional) Specifies whether email addresses or phone numbers can be specified as usernames when a user signs up. Conflicts with `alias_attributes`. -* `user_pool_add_ons` - (Optional) The configuration for [user pool add-ons](#user-pool-add-ons). +* `user_pool_add_ons` - (Optional) Configuration block for [user pool add-ons](#user-pool-add-ons) to enable user pool advanced security mode features. * `verification_message_template` (Optional) - The [verification message templates](#verification-message-template) configuration. #### Admin Create User Config