Skip to content

Commit

Permalink
PR fixes: refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
rtim75 committed Dec 14, 2021
1 parent 3b2d087 commit 1952176
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 110 deletions.
153 changes: 49 additions & 104 deletions internal/service/cognitoidp/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
Expand Down Expand Up @@ -39,14 +40,15 @@ func ResourceUser() *schema.Resource {
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
},
"creation_date": {
Type: schema.TypeString,
Computed: true,
},
"desired_delivery_mediums": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
cognitoidentityprovider.DeliveryMediumTypeSms,
cognitoidentityprovider.DeliveryMediumTypeEmail,
}, false),
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(cognitoidentityprovider.DeliveryMediumType_Values(), false),
},
Optional: true,
},
Expand All @@ -59,34 +61,26 @@ func ResourceUser() *schema.Resource {
Type: schema.TypeBool,
Optional: true,
},
"message_action": {
"last_modified_date": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
cognitoidentityprovider.MessageActionTypeResend,
cognitoidentityprovider.MessageActionTypeSuppress,
}, false),
Computed: true,
},
"message_action": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(cognitoidentityprovider.MessageActionType_Values(), false),
},
"mfa_preference": {
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sms_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"software_token_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"preferred_mfa": {
Type: schema.TypeString,
Computed: true,
},
},
"mfa_setting_list": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
},
"preferred_mfa_setting": {
Type: schema.TypeString,
Computed: true,
},
"user_pool_id": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -161,14 +155,14 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {

if v, ok := d.GetOk("attributes"); ok {
attributes := v.(map[string]interface{})
params.UserAttributes = expandUserAttributes(attributes)
params.UserAttributes = expandAttribute(attributes)
}

if v, ok := d.GetOk("validation_data"); ok {
attributes := v.(map[string]interface{})
// aws sdk uses the same type for both validation data and user attributes
// https://docs.aws.amazon.com/sdk-for-go/api/service/cognitoidentityprovider/#AdminCreateUserInput
params.ValidationData = expandUserAttributes(attributes)
params.ValidationData = expandAttribute(attributes)
}

if v, ok := d.GetOk("temporary_password"); ok {
Expand All @@ -177,15 +171,10 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {

resp, err := conn.AdminCreateUser(params)
if err != nil {
if tfawserr.ErrMessageContains(err, cognitoidentityprovider.ErrCodeUsernameExistsException, "An account with the email already exists") {
log.Println("[ERROR] User alias already exists. To override the alias set `force_alias_creation` attribute to `true`.")
} else if tfawserr.ErrMessageContains(err, cognitoidentityprovider.ErrCodeInvalidParameterException, "No email provided but desired delivery medium was Email") {
log.Println("[ERROR] No email provided but desired delivery medium was `EMAIL`.")
}
return fmt.Errorf("Error creating Cognito User: %s", err)
return fmt.Errorf("Error creating Cognito User (%s): %w", d.Id(), err)
}

d.SetId(fmt.Sprintf("%s/%s", *params.UserPoolId, *resp.User.Username))
d.SetId(fmt.Sprintf("%s/%s", aws.StringValue(params.UserPoolId), aws.StringValue(resp.User.Username)))

if v := d.Get("enabled"); !v.(bool) {
disableParams := &cognitoidentityprovider.AdminDisableUserInput{
Expand All @@ -195,7 +184,7 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {

_, err := conn.AdminDisableUser(disableParams)
if err != nil {
return fmt.Errorf("Error disabling Cognito User: %s", err)
return fmt.Errorf("Error disabling Cognito User (%s): %w", d.Id(), err)
}
}

Expand All @@ -209,7 +198,7 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {

_, err := conn.AdminSetUserPassword(setPasswordParams)
if err != nil {
return fmt.Errorf("Error setting Cognito User's password: %s", err)
return fmt.Errorf("Error setting Cognito User's password (%s): %w", d.Id(), err)
}
}

Expand All @@ -228,33 +217,28 @@ func resourceUserRead(d *schema.ResourceData, meta interface{}) error {

user, err := conn.AdminGetUser(params)
if err != nil {
if tfawserr.ErrMessageContains(err, "UserNotFoundException", "") {
if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeUserNotFoundException) {
log.Printf("[WARN] Cognito User %s not found, removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error reading Cognito User: %s", err)
return fmt.Errorf("Error reading Cognito User (%s): %w", d.Id(), err)
}

if err := d.Set("attributes", flattenUserAttributes(user.UserAttributes)); err != nil {
return fmt.Errorf("failed setting user attributes: %w", err)
return fmt.Errorf("failed setting user attributes (%s): %w", d.Id(), err)
}

if err := d.Set("status", user.UserStatus); err != nil {
return fmt.Errorf("failed setting user status: %w", err)
if err := d.Set("mfa_setting_list", user.UserMFASettingList); err != nil {
return fmt.Errorf("failed setting user's mfa settings (%s): %w", d.Id(), err)
}

if err := d.Set("sub", flattenUserSub(user.UserAttributes)); err != nil {
return fmt.Errorf("failed setting user sub: %w", err)
}

if err := d.Set("enabled", user.Enabled); err != nil {
return fmt.Errorf("failed setting user enabled status: %w", err)
}

if err := d.Set("mfa_preference", flattenUserMfaPreference(user.MFAOptions, user.UserMFASettingList, user.PreferredMfaSetting)); err != nil {
return fmt.Errorf("failed setting user mfa_preference: %w", err)
}
d.Set("preferred_mfa_setting", aws.StringValue(user.PreferredMfaSetting))
d.Set("status", aws.StringValue(user.UserStatus))
d.Set("enabled", aws.BoolValue(user.Enabled))
d.Set("creation_date", user.UserCreateDate.Format(time.RFC3339))
d.Set("last_modified_date", user.UserLastModifiedDate.Format(time.RFC3339))
d.Set("sub", retrieveUserSub(user.UserAttributes))

return nil
}
Expand All @@ -273,16 +257,11 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
params := &cognitoidentityprovider.AdminUpdateUserAttributesInput{
Username: aws.String(d.Get("username").(string)),
UserPoolId: aws.String(d.Get("user_pool_id").(string)),
UserAttributes: expandUserAttributes(upd),
UserAttributes: expandAttribute(upd),
}
_, err := conn.AdminUpdateUserAttributes(params)
if err != nil {
if tfawserr.ErrMessageContains(err, "UserNotFoundException", "") {
log.Printf("[WARN] Cognito User %s is already gone", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error updating Cognito User Attributes: %s", err)
return fmt.Errorf("Error updating Cognito User Attributes (%s): %w", d.Id(), err)
}
}
if len(del) > 0 {
Expand All @@ -293,12 +272,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
}
_, err := conn.AdminDeleteUserAttributes(params)
if err != nil {
if tfawserr.ErrMessageContains(err, "UserNotFoundException", "") {
log.Printf("[WARN] Cognito User %s is already gone", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error updating Cognito User Attributes: %s", err)
return fmt.Errorf("Error updating Cognito User Attributes (%s): %w", d.Id(), err)
}
}
}
Expand All @@ -313,7 +287,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
}
_, err := conn.AdminEnableUser(enableParams)
if err != nil {
return fmt.Errorf("Error enabling Cognito User: %s", err)
return fmt.Errorf("Error enabling Cognito User (%s): %w", d.Id(), err)
}
} else {
disableParams := &cognitoidentityprovider.AdminDisableUserInput{
Expand All @@ -322,7 +296,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
}
_, err := conn.AdminDisableUser(disableParams)
if err != nil {
return fmt.Errorf("Error disabling Cognito User: %s", err)
return fmt.Errorf("Error disabling Cognito User (%s): %w", d.Id(), err)
}
}
}
Expand All @@ -340,7 +314,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {

_, err := conn.AdminSetUserPassword(setPasswordParams)
if err != nil {
return fmt.Errorf("Error changing Cognito User's password: %s", err)
return fmt.Errorf("Error changing Cognito User's temporary password (%s): %w", d.Id(), err)
}
} else {
d.Set("temporary_password", nil)
Expand All @@ -360,7 +334,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {

_, err := conn.AdminSetUserPassword(setPasswordParams)
if err != nil {
return fmt.Errorf("Error changing Cognito User's password: %s", err)
return fmt.Errorf("Error changing Cognito User's password (%s): %w", d.Id(), err)
}
} else {
d.Set("password", nil)
Expand All @@ -382,7 +356,7 @@ func resourceUserDelete(d *schema.ResourceData, meta interface{}) error {

_, err := conn.AdminDeleteUser(params)
if err != nil {
return fmt.Errorf("Error deleting Cognito User: %s", err)
return fmt.Errorf("Error deleting Cognito User (%s): %w", d.Id(), err)
}

return nil
Expand All @@ -400,7 +374,7 @@ func resourceUserImport(d *schema.ResourceData, meta interface{}) ([]*schema.Res
return []*schema.ResourceData{d}, nil
}

func expandUserAttributes(tfMap map[string]interface{}) []*cognitoidentityprovider.AttributeType {
func expandAttribute(tfMap map[string]interface{}) []*cognitoidentityprovider.AttributeType {
if len(tfMap) == 0 {
return nil
}
Expand Down Expand Up @@ -498,7 +472,7 @@ func expandUserDesiredDeliveryMediums(tfSet *schema.Set) []*string {
return apiList
}

func flattenUserSub(apiList []*cognitoidentityprovider.AttributeType) string {
func retrieveUserSub(apiList []*cognitoidentityprovider.AttributeType) string {
for _, attr := range apiList {
if aws.StringValue(attr.Name) == "sub" {
return aws.StringValue(attr.Value)
Expand All @@ -518,35 +492,6 @@ func expandUserClientMetadata(tfMap map[string]interface{}) map[string]*string {
return apiMap
}

func flattenUserMfaPreference(mfaOptions []*cognitoidentityprovider.MFAOptionType, mfaSettingsList []*string, preferredMfa *string) []interface{} {
preference := map[string]interface{}{}

for _, setting := range mfaSettingsList {
v := aws.StringValue(setting)

if v == cognitoidentityprovider.ChallengeNameTypeSmsMfa {
preference["sms_enabled"] = true
} else if v == cognitoidentityprovider.ChallengeNameTypeSoftwareTokenMfa {
preference["software_token_enabled"] = true
}
}

if len(mfaOptions) > 0 {
// mfaOptions.DeliveryMediums can only have value SMS so we check only first element
if aws.StringValue(mfaOptions[0].DeliveryMedium) == cognitoidentityprovider.DeliveryMediumTypeSms {
preference["sms_enabled"] = true
}
}

preference["preferred_mfa"] = aws.StringValue(preferredMfa)

return []interface{}{preference}
}

func userAttributeHash(attr interface{}) int {
return schema.HashString(attr.(map[string]interface{})["name"])
}

func UserAttributeKeyMatchesStandardAttribute(input string) bool {
if len(input) == 0 {
return false
Expand Down
11 changes: 6 additions & 5 deletions internal/service/cognitoidp/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ func TestAccCognitoUser_basic(t *testing.T) {
Config: testAccUserConfigBasic(rUserPoolName, rUserName),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserExists(resourceName),
resource.TestCheckResourceAttrSet(resourceName, "creation_date"),
resource.TestCheckResourceAttrSet(resourceName, "last_modified_date"),
resource.TestCheckResourceAttrSet(resourceName, "sub"),
resource.TestCheckResourceAttr(resourceName, "preferred_mfa_setting", ""),
resource.TestCheckResourceAttr(resourceName, "mfa_setting_list.#", "0"),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "status", cognitoidentityprovider.UserStatusTypeForceChangePassword),
resource.TestCheckResourceAttr(resourceName, "mfa_preference.0.sms_enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "mfa_preference.0.software_token_enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "mfa_preference.0.preferred_mfa", ""),
),
},
{
Expand Down Expand Up @@ -332,7 +333,7 @@ func testAccCheckUserDestroy(s *terraform.State) error {
_, err := conn.AdminGetUser(params)

if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" {
if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == cognitoidentityprovider.ErrCodeUserNotFoundException || awsErr.Code() == cognitoidentityprovider.ErrCodeResourceNotFoundException) {
return nil
}
return err
Expand Down Expand Up @@ -628,7 +629,7 @@ resource "aws_cognito_user_pool" "test" {
resource "aws_cognito_user" "test" {
user_pool_id = aws_cognito_user_pool.test.id
username = %[2]q
enabled = %t
enabled = %[3]t
}
`, userPoolName, userName, enabled)
}
3 changes: 2 additions & 1 deletion website/docs/r/cognito_user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Provides a Cognito User Resource.
## Example Usage

### Basic configuration

```terraform
resource "aws_cognito_user_pool" "example" {
name = "MyExamplePool"
Expand Down Expand Up @@ -70,7 +71,7 @@ The following arguments are required:

The following arguments are optional:

* `attributes` - (Optional) An array of name-value pairs that contain user attributes and attribute values to be set for the user to be created.
* `attributes` - (Optional) A map that contains user attributes and attribute values to be set for the user to be created.
* `client_metadata` - (Optional) A map of custom key-value pairs that you can provide as input for any custom workflows that user creation triggers. Amazon Cognito does not store the `client_metadata` value. This data is available only to Lambda triggers that are assigned to a user pool to support custom workflows. If your user pool configuration does not include triggers, the ClientMetadata parameter serves no purpose. For more information, see [Customizing User Pool Workflows with Lambda Triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html).
* `desired_delivery_mediums` - (Optional) A list of mediums to the welcome message will be sent through. Allowed values are `EMAIL` and `SMS`. If it's provided, make sure you have also specified `email` attribute for the `EMAIL` medium and `phone_number` for the `SMS`. More than one value can be specified. Amazon Cognito does not store the `desired_delivery_mediums` value. Defaults to `["SMS"]`.
* `enabled` - (Optional) Specifies whether the user should be enabled after creation. The welcome message will be sent regardless of the `enabled` value. The behavior can be changed with `message_action` argument. Defaults to `true`.
Expand Down

0 comments on commit 1952176

Please sign in to comment.