diff --git a/.changelog/14935.txt b/.changelog/14935.txt new file mode 100644 index 00000000000..e44d7120eea --- /dev/null +++ b/.changelog/14935.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_cognito_user_pool_client: Add plan time validation for `name`, `default_redirect_uri`, `supported_identity_providers` +``` + +```release-note:enhancement +resource/aws_cognito_user_pool_client: Add support for `access_token_validity` and `id_token_validity`, `token_validity_units` +``` + +```release-note:enhancement +resource/aws_cognito_user_pool: Add support for `configuration_set` in `email_configuration` +``` diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 341ee3043f1..d4c62a7f92f 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -27,6 +27,33 @@ func resourceAwsCognitoUserPool() *schema.Resource { // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html Schema: map[string]*schema.Schema{ + "account_recovery_setting": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "recovery_mechanism": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.RecoveryOptionNameType_Values(), false), + }, + "priority": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, "admin_create_user_config": { Type: schema.TypeList, Optional: true, @@ -65,44 +92,32 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "alias_attributes": { Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.AliasAttributeTypeEmail, - cognitoidentityprovider.AliasAttributeTypePhoneNumber, - cognitoidentityprovider.AliasAttributeTypePreferredUsername, - }, false), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.AliasAttributeType_Values(), false), }, ConflictsWith: []string{"username_attributes"}, }, - "arn": { Type: schema.TypeString, Computed: true, }, - "auto_verified_attributes": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.VerifiedAttributeTypePhoneNumber, - cognitoidentityprovider.VerifiedAttributeTypeEmail, - }, false), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.VerifiedAttributeType_Values(), false), }, }, - "creation_date": { Type: schema.TypeString, Computed: true, }, - "device_configuration": { Type: schema.TypeList, Optional: true, @@ -120,7 +135,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "email_configuration": { Type: schema.TypeList, Optional: true, @@ -128,6 +142,20 @@ func resourceAwsCognitoUserPool() *schema.Resource { DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "configuration_set": { + Type: schema.TypeString, + Optional: true, + }, + "email_sending_account": { + Type: schema.TypeString, + Optional: true, + Default: cognitoidentityprovider.EmailSendingAccountTypeCognitoDefault, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.EmailSendingAccountType_Values(), false), + }, + "from_email_address": { + Type: schema.TypeString, + Optional: true, + }, "reply_to_email_address": { Type: schema.TypeString, Optional: true, @@ -142,23 +170,9 @@ func resourceAwsCognitoUserPool() *schema.Resource { Optional: true, ValidateFunc: validateArn, }, - "from_email_address": { - Type: schema.TypeString, - Optional: true, - }, - "email_sending_account": { - Type: schema.TypeString, - Optional: true, - Default: cognitoidentityprovider.EmailSendingAccountTypeCognitoDefault, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.EmailSendingAccountTypeCognitoDefault, - cognitoidentityprovider.EmailSendingAccountTypeDeveloper, - }, false), - }, }, }, }, - "email_verification_subject": { Type: schema.TypeString, Optional: true, @@ -166,7 +180,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { ValidateFunc: validateCognitoUserPoolEmailVerificationSubject, ConflictsWith: []string{"verification_message_template.0.email_subject"}, }, - "email_verification_message": { Type: schema.TypeString, Optional: true, @@ -174,12 +187,10 @@ func resourceAwsCognitoUserPool() *schema.Resource { ValidateFunc: validateCognitoUserPoolEmailVerificationMessage, ConflictsWith: []string{"verification_message_template.0.email_message"}, }, - "endpoint": { Type: schema.TypeString, Computed: true, }, - "lambda_config": { Type: schema.TypeList, Optional: true, @@ -240,29 +251,21 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "last_modified_date": { Type: schema.TypeString, Computed: true, }, - "mfa_configuration": { - Type: schema.TypeString, - Optional: true, - Default: cognitoidentityprovider.UserPoolMfaTypeOff, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.UserPoolMfaTypeOff, - cognitoidentityprovider.UserPoolMfaTypeOn, - cognitoidentityprovider.UserPoolMfaTypeOptional, - }, false), + Type: schema.TypeString, + Optional: true, + Default: cognitoidentityprovider.UserPoolMfaTypeOff, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.UserPoolMfaType_Values(), false), }, - "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "password_policy": { Type: schema.TypeList, Optional: true, @@ -299,7 +302,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "schema": { Type: schema.TypeSet, Optional: true, @@ -309,15 +311,10 @@ func resourceAwsCognitoUserPool() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "attribute_data_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.AttributeDataTypeString, - cognitoidentityprovider.AttributeDataTypeNumber, - cognitoidentityprovider.AttributeDataTypeDateTime, - cognitoidentityprovider.AttributeDataTypeBoolean, - }, false), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.AttributeDataType_Values(), false), }, "developer_only_attribute": { Type: schema.TypeBool, @@ -383,13 +380,11 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "sms_authentication_message": { Type: schema.TypeString, Optional: true, ValidateFunc: validateCognitoUserPoolSmsAuthenticationMessage, }, - "sms_configuration": { Type: schema.TypeList, Optional: true, @@ -409,7 +404,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "sms_verification_message": { Type: schema.TypeString, Optional: true, @@ -417,7 +411,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { ValidateFunc: validateCognitoUserPoolSmsVerificationMessage, ConflictsWith: []string{"verification_message_template.0.sms_message"}, }, - "software_token_mfa_configuration": { Type: schema.TypeList, Optional: true, @@ -432,23 +425,17 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "tags": tagsSchema(), - "username_attributes": { Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.UsernameAttributeTypeEmail, - cognitoidentityprovider.UsernameAttributeTypePhoneNumber, - }, false), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.UsernameAttributeType_Values(), false), }, ConflictsWith: []string{"alias_attributes"}, }, - "username_configuration": { Type: schema.TypeList, Optional: true, @@ -463,7 +450,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "user_pool_add_ons": { Type: schema.TypeList, Optional: true, @@ -471,18 +457,13 @@ func resourceAwsCognitoUserPool() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "advanced_security_mode": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.AdvancedSecurityModeTypeAudit, - cognitoidentityprovider.AdvancedSecurityModeTypeEnforced, - cognitoidentityprovider.AdvancedSecurityModeTypeOff, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.AdvancedSecurityModeType_Values(), false), }, }, }, }, - "verification_message_template": { Type: schema.TypeList, Optional: true, @@ -491,13 +472,10 @@ func resourceAwsCognitoUserPool() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "default_email_option": { - Type: schema.TypeString, - Optional: true, - Default: cognitoidentityprovider.DefaultEmailOptionTypeConfirmWithCode, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.DefaultEmailOptionTypeConfirmWithLink, - cognitoidentityprovider.DefaultEmailOptionTypeConfirmWithCode, - }, false), + Type: schema.TypeString, + Optional: true, + Default: cognitoidentityprovider.DefaultEmailOptionTypeConfirmWithCode, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.DefaultEmailOptionType_Values(), false), }, "email_message": { Type: schema.TypeString, @@ -535,33 +513,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, }, - "account_recovery_setting": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "recovery_mechanism": { - Type: schema.TypeSet, - Required: true, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(cognitoidentityprovider.RecoveryOptionNameType_Values(), false), - }, - "priority": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - }, - }, - }, }, } } @@ -622,6 +573,10 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) emailConfigurationType.EmailSendingAccount = aws.String(v.(string)) } + if v, ok := config["configuration_set"]; ok && v.(string) != "" { + emailConfigurationType.ConfigurationSet = aws.String(v.(string)) + } + params.EmailConfiguration = emailConfigurationType } } @@ -1076,6 +1031,10 @@ func resourceAwsCognitoUserPoolUpdate(d *schema.ResourceData, meta interface{}) emailConfigurationType.From = aws.String(v.(string)) } + if v, ok := config["configuration_set"]; ok && v.(string) != "" { + emailConfigurationType.ConfigurationSet = aws.String(v.(string)) + } + params.EmailConfiguration = emailConfigurationType } } @@ -1190,7 +1149,7 @@ func resourceAwsCognitoUserPoolUpdate(d *schema.ResourceData, meta interface{}) _, err = conn.UpdateUserPool(params) } if err != nil { - return fmt.Errorf("Error updating Cognito User pool: %s", err) + return fmt.Errorf("error updating Cognito User pool (%s): %w", d.Id(), err) } } @@ -1209,7 +1168,7 @@ func resourceAwsCognitoUserPoolDelete(d *schema.ResourceData, meta interface{}) _, err := conn.DeleteUserPool(params) if err != nil { - return fmt.Errorf("Error deleting user pool: %s", err) + return fmt.Errorf("error deleting Cognito user pool (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_cognito_user_pool_client.go b/aws/resource_aws_cognito_user_pool_client.go index e2132390e5a..49a98fc2b7c 100644 --- a/aws/resource_aws_cognito_user_pool_client.go +++ b/aws/resource_aws_cognito_user_pool_client.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "strings" "github.com/aws/aws-sdk-go/aws" @@ -24,61 +25,10 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - - "client_secret": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - - "generate_secret": { - Type: schema.TypeBool, + "access_token_validity": { + Type: schema.TypeInt, Optional: true, - ForceNew: true, - }, - - "user_pool_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "explicit_auth_flows": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice(cognitoidentityprovider.ExplicitAuthFlowsType_Values(), false), - }, }, - - "read_attributes": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - - "write_attributes": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - - "refresh_token_validity": { - Type: schema.TypeInt, - Optional: true, - Default: 30, - ValidateFunc: validation.IntBetween(0, 3650), - }, - "allowed_oauth_flows": { Type: schema.TypeSet, Optional: true, @@ -88,12 +38,10 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { ValidateFunc: validation.StringInSlice(cognitoidentityprovider.OAuthFlowType_Values(), false), }, }, - "allowed_oauth_flows_user_pool_client": { Type: schema.TypeBool, Optional: true, }, - "allowed_oauth_scopes": { Type: schema.TypeSet, Optional: true, @@ -106,83 +54,180 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { // Constraints seem like to be designed for custom scopes which are not supported yet? }, }, - + "analytics_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "application_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"analytics_configuration.0.application_id", "analytics_configuration.0.application_arn"}, + }, + "application_arn": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"analytics_configuration.0.application_id", "analytics_configuration.0.application_arn"}, + ConflictsWith: []string{"analytics_configuration.0.external_id", "analytics_configuration.0.role_arn"}, + ValidateFunc: validateArn, + }, + "external_id": { + Type: schema.TypeString, + ConflictsWith: []string{"analytics_configuration.0.application_arn"}, + Optional: true, + }, + "role_arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"analytics_configuration.0.application_arn"}, + ValidateFunc: validateArn, + }, + "user_data_shared": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, "callback_urls": { Type: schema.TypeSet, Optional: true, MaxItems: 100, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateCognitoUserPoolClientURL, + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`), + "must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+`"), + ), }, }, - + "client_secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, "default_redirect_uri": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`), + "must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+`"), + ), + }, + "explicit_auth_flows": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.ExplicitAuthFlowsType_Values(), false), + }, + }, + "generate_secret": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "id_token_validity": { + Type: schema.TypeInt, + Optional: true, }, - "logout_urls": { Type: schema.TypeSet, Optional: true, MaxItems: 100, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateCognitoUserPoolClientURL, + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`), + "must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+`"), + ), }, }, - - "prevent_user_existence_errors": { + "name": { Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`[\w\s+=,.@-]+`), + "must satisfy regular expression pattern: `[\\w\\s+=,.@-]+`"), + ), + }, + "prevent_user_existence_errors": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.PreventUserExistenceErrorTypes_Values(), false), + }, + "read_attributes": { + Type: schema.TypeSet, Optional: true, - Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "refresh_token_validity": { + Type: schema.TypeInt, + Optional: true, + Default: 30, + ValidateFunc: validation.IntBetween(0, 3650), }, - "supported_identity_providers": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 32), + validation.StringMatch(regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`), + "must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+`"), + ), }, }, - "analytics_configuration": { + "token_validity_units": { Type: schema.TypeList, Optional: true, MaxItems: 1, - MinItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "application_id": { + "access_token": { Type: schema.TypeString, Optional: true, - ExactlyOneOf: []string{"analytics_configuration.0.application_id", "analytics_configuration.0.application_arn"}, - }, - "application_arn": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"analytics_configuration.0.application_id", "analytics_configuration.0.application_arn"}, - ConflictsWith: []string{"analytics_configuration.0.external_id", "analytics_configuration.0.role_arn"}, - ValidateFunc: validateArn, + Default: cognitoidentityprovider.TimeUnitsTypeHours, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.TimeUnitsType_Values(), false), }, - "external_id": { - Type: schema.TypeString, - ConflictsWith: []string{"analytics_configuration.0.application_arn"}, - Optional: true, - }, - "role_arn": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ConflictsWith: []string{"analytics_configuration.0.application_arn"}, - ValidateFunc: validateArn, + "id_token": { + Type: schema.TypeString, + Optional: true, + Default: cognitoidentityprovider.TimeUnitsTypeHours, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.TimeUnitsType_Values(), false), }, - "user_data_shared": { - Type: schema.TypeBool, - Optional: true, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + Default: cognitoidentityprovider.TimeUnitsTypeDays, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.TimeUnitsType_Values(), false), }, }, }, }, + "user_pool_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "write_attributes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, }, } } @@ -215,6 +260,14 @@ func resourceAwsCognitoUserPoolClientCreate(d *schema.ResourceData, meta interfa params.RefreshTokenValidity = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("access_token_validity"); ok { + params.AccessTokenValidity = aws.Int64(int64(v.(int))) + } + + if v, ok := d.GetOk("id_token_validity"); ok { + params.IdTokenValidity = aws.Int64(int64(v.(int))) + } + if v, ok := d.GetOk("allowed_oauth_flows"); ok { params.AllowedOAuthFlows = expandStringSet(v.(*schema.Set)) } @@ -247,6 +300,10 @@ func resourceAwsCognitoUserPoolClientCreate(d *schema.ResourceData, meta interfa params.AnalyticsConfiguration = expandAwsCognitoUserPoolClientAnalyticsConfig(v.([]interface{})) } + if v, ok := d.GetOk("token_validity_units"); ok { + params.TokenValidityUnits = expandAwsCognitoUserPoolClientTokenValidityUnitsType(v.([]interface{})) + } + if v, ok := d.GetOk("prevent_user_existence_errors"); ok { params.PreventUserExistenceErrors = aws.String(v.(string)) } @@ -256,7 +313,7 @@ func resourceAwsCognitoUserPoolClientCreate(d *schema.ResourceData, meta interfa resp, err := conn.CreateUserPoolClient(params) if err != nil { - return fmt.Errorf("Error creating Cognito User Pool Client: %s", err) + return fmt.Errorf("error creating Cognito User Pool Client (%s): %w", d.Get("name").(string), err) } d.SetId(aws.StringValue(resp.UserPoolClient.ClientId)) @@ -285,25 +342,31 @@ func resourceAwsCognitoUserPoolClientRead(d *schema.ResourceData, meta interface return err } - d.SetId(aws.StringValue(resp.UserPoolClient.ClientId)) - d.Set("user_pool_id", resp.UserPoolClient.UserPoolId) - d.Set("name", resp.UserPoolClient.ClientName) - d.Set("explicit_auth_flows", flattenStringSet(resp.UserPoolClient.ExplicitAuthFlows)) - d.Set("read_attributes", flattenStringSet(resp.UserPoolClient.ReadAttributes)) - d.Set("write_attributes", flattenStringSet(resp.UserPoolClient.WriteAttributes)) - d.Set("refresh_token_validity", resp.UserPoolClient.RefreshTokenValidity) - d.Set("client_secret", resp.UserPoolClient.ClientSecret) - d.Set("allowed_oauth_flows", flattenStringSet(resp.UserPoolClient.AllowedOAuthFlows)) - d.Set("allowed_oauth_flows_user_pool_client", resp.UserPoolClient.AllowedOAuthFlowsUserPoolClient) - d.Set("allowed_oauth_scopes", flattenStringSet(resp.UserPoolClient.AllowedOAuthScopes)) - d.Set("callback_urls", flattenStringSet(resp.UserPoolClient.CallbackURLs)) - d.Set("default_redirect_uri", resp.UserPoolClient.DefaultRedirectURI) - d.Set("logout_urls", flattenStringSet(resp.UserPoolClient.LogoutURLs)) - d.Set("prevent_user_existence_errors", resp.UserPoolClient.PreventUserExistenceErrors) - d.Set("supported_identity_providers", flattenStringSet(resp.UserPoolClient.SupportedIdentityProviders)) - - if err := d.Set("analytics_configuration", flattenAwsCognitoUserPoolClientAnalyticsConfig(resp.UserPoolClient.AnalyticsConfiguration)); err != nil { - return fmt.Errorf("error setting analytics_configuration: %s", err) + userPoolClient := resp.UserPoolClient + d.Set("user_pool_id", userPoolClient.UserPoolId) + d.Set("name", userPoolClient.ClientName) + d.Set("explicit_auth_flows", flattenStringSet(userPoolClient.ExplicitAuthFlows)) + d.Set("read_attributes", flattenStringSet(userPoolClient.ReadAttributes)) + d.Set("write_attributes", flattenStringSet(userPoolClient.WriteAttributes)) + d.Set("refresh_token_validity", userPoolClient.RefreshTokenValidity) + d.Set("access_token_validity", userPoolClient.AccessTokenValidity) + d.Set("id_token_validity", userPoolClient.IdTokenValidity) + d.Set("client_secret", userPoolClient.ClientSecret) + d.Set("allowed_oauth_flows", flattenStringSet(userPoolClient.AllowedOAuthFlows)) + d.Set("allowed_oauth_flows_user_pool_client", userPoolClient.AllowedOAuthFlowsUserPoolClient) + d.Set("allowed_oauth_scopes", flattenStringSet(userPoolClient.AllowedOAuthScopes)) + d.Set("callback_urls", flattenStringSet(userPoolClient.CallbackURLs)) + d.Set("default_redirect_uri", userPoolClient.DefaultRedirectURI) + d.Set("logout_urls", flattenStringSet(userPoolClient.LogoutURLs)) + d.Set("prevent_user_existence_errors", userPoolClient.PreventUserExistenceErrors) + d.Set("supported_identity_providers", flattenStringSet(userPoolClient.SupportedIdentityProviders)) + + if err := d.Set("analytics_configuration", flattenAwsCognitoUserPoolClientAnalyticsConfig(userPoolClient.AnalyticsConfiguration)); err != nil { + return fmt.Errorf("error setting analytics_configuration: %w", err) + } + + if err := d.Set("token_validity_units", flattenAwsCognitoUserPoolClientTokenValidityUnitsType(userPoolClient.TokenValidityUnits)); err != nil { + return fmt.Errorf("error setting token_validity_units: %w", err) } return nil @@ -337,6 +400,14 @@ func resourceAwsCognitoUserPoolClientUpdate(d *schema.ResourceData, meta interfa params.RefreshTokenValidity = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("access_token_validity"); ok { + params.AccessTokenValidity = aws.Int64(int64(v.(int))) + } + + if v, ok := d.GetOk("id_token_validity"); ok { + params.IdTokenValidity = aws.Int64(int64(v.(int))) + } + if v, ok := d.GetOk("allowed_oauth_flows"); ok { params.AllowedOAuthFlows = expandStringSet(v.(*schema.Set)) } @@ -373,11 +444,15 @@ func resourceAwsCognitoUserPoolClientUpdate(d *schema.ResourceData, meta interfa params.AnalyticsConfiguration = expandAwsCognitoUserPoolClientAnalyticsConfig(v.([]interface{})) } + if v, ok := d.GetOk("token_validity_units"); ok { + params.TokenValidityUnits = expandAwsCognitoUserPoolClientTokenValidityUnitsType(v.([]interface{})) + } + log.Printf("[DEBUG] Updating Cognito User Pool Client: %s", params) _, err := conn.UpdateUserPoolClient(params) if err != nil { - return fmt.Errorf("Error updating Cognito User Pool Client: %s", err) + return fmt.Errorf("error updating Cognito User Pool Client (%s): %w", d.Id(), err) } return resourceAwsCognitoUserPoolClientRead(d, meta) @@ -396,7 +471,7 @@ func resourceAwsCognitoUserPoolClientDelete(d *schema.ResourceData, meta interfa _, err := conn.DeleteUserPoolClient(params) if err != nil { - return fmt.Errorf("Error deleting Cognito User Pool Client: %s", err) + return fmt.Errorf("error deleting Cognito User Pool Client (%s): %w", d.Id(), err) } return nil @@ -404,7 +479,7 @@ func resourceAwsCognitoUserPoolClientDelete(d *schema.ResourceData, meta interfa func resourceAwsCognitoUserPoolClientImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { if len(strings.Split(d.Id(), "/")) != 2 || len(d.Id()) < 3 { - return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'user-pool-id/client-id'", d.Id()) + return []*schema.ResourceData{}, fmt.Errorf("wrong format of resource: %s. Please follow 'user-pool-id/client-id'", d.Id()) } userPoolId := strings.Split(d.Id(), "/")[0] clientId := strings.Split(d.Id(), "/")[1] @@ -474,3 +549,54 @@ func flattenAwsCognitoUserPoolClientAnalyticsConfig(analyticsConfig *cognitoiden return []interface{}{m} } + +func expandAwsCognitoUserPoolClientTokenValidityUnitsType(l []interface{}) *cognitoidentityprovider.TokenValidityUnitsType { + if len(l) == 0 { + return nil + } + + m := l[0].(map[string]interface{}) + + tokenValidityConfig := &cognitoidentityprovider.TokenValidityUnitsType{} + + if v, ok := m["access_token"]; ok { + tokenValidityConfig.AccessToken = aws.String(v.(string)) + } + + if v, ok := m["id_token"]; ok { + tokenValidityConfig.IdToken = aws.String(v.(string)) + } + + if v, ok := m["refresh_token"]; ok { + tokenValidityConfig.RefreshToken = aws.String(v.(string)) + } + + return tokenValidityConfig +} + +func flattenAwsCognitoUserPoolClientTokenValidityUnitsType(tokenValidityConfig *cognitoidentityprovider.TokenValidityUnitsType) []interface{} { + if tokenValidityConfig == nil { + return nil + } + + //tokenValidityConfig is never nil and if everything is empty it causes diffs + if tokenValidityConfig.IdToken == nil && tokenValidityConfig.AccessToken == nil && tokenValidityConfig.RefreshToken == nil { + return nil + } + + m := map[string]interface{}{} + + if tokenValidityConfig.IdToken != nil { + m["id_token"] = aws.StringValue(tokenValidityConfig.IdToken) + } + + if tokenValidityConfig.AccessToken != nil { + m["access_token"] = aws.StringValue(tokenValidityConfig.AccessToken) + } + + if tokenValidityConfig.RefreshToken != nil { + m["refresh_token"] = aws.StringValue(tokenValidityConfig.RefreshToken) + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index d1fff425c1b..c6f90a14c5a 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -30,6 +30,8 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", clientName), resource.TestCheckResourceAttr(resourceName, "explicit_auth_flows.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "ADMIN_NO_SRP_AUTH"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "0"), + resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "0"), ), }, { @@ -42,7 +44,7 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { }) } -func TestAccAWSCognitoUserPoolClient_RefreshTokenValidity(t *testing.T) { +func TestAccAWSCognitoUserPoolClient_refreshTokenValidity(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" @@ -76,6 +78,156 @@ func TestAccAWSCognitoUserPoolClient_RefreshTokenValidity(t *testing.T) { }) } +func TestAccAWSCognitoUserPoolClient_accessTokenValidity(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientConfigAccessTokenValidity(rName, 5), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "access_token_validity", "5"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolClientConfigAccessTokenValidity(rName, 1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "access_token_validity", "1"), + ), + }, + }, + }) +} + +func TestAccAWSCognitoUserPoolClient_idTokenValidity(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientConfigIDTokenValidity(rName, 5), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "id_token_validity", "5"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolClientConfigIDTokenValidity(rName, 1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "id_token_validity", "1"), + ), + }, + }, + }) +} + +func TestAccAWSCognitoUserPoolClient_tokenValidityUnits(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientConfigTokenValidityUnits(rName, "days"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "1"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.access_token", "days"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.id_token", "days"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.refresh_token", "days"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolClientConfigTokenValidityUnits(rName, "hours"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "1"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.access_token", "hours"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.id_token", "hours"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.refresh_token", "hours"), + ), + }, + }, + }) +} + +func TestAccAWSCognitoUserPoolClient_tokenValidityUnitsWTokenValidity(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientConfigTokenValidityUnitsWithTokenValidity(rName, "days"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "1"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.access_token", "days"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.id_token", "days"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.refresh_token", "days"), + resource.TestCheckResourceAttr(resourceName, "id_token_validity", "1"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolClientConfigTokenValidityUnitsWithTokenValidity(rName, "hours"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "1"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.access_token", "hours"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.id_token", "hours"), + resource.TestCheckResourceAttr(resourceName, "token_validity_units.0.refresh_token", "hours"), + resource.TestCheckResourceAttr(resourceName, "id_token_validity", "1"), + ), + }, + }, + }) +} + func TestAccAWSCognitoUserPoolClient_Name(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType rName := acctest.RandomWithPrefix("tf-acc-test") @@ -230,6 +382,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) clientName := acctest.RandString(10) resourceName := "aws_cognito_user_pool_client.test" + pinpointResourceName := "aws_pinpoint_app.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -237,6 +390,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { testAccPreCheckAWSCognitoIdentityProvider(t) testAccPreCheckAWSPinpointApp(t) }, + ErrorCheck: testAccErrorCheckSkipCognito(t), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ @@ -245,6 +399,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "analytics_configuration.0.application_id", pinpointResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", clientName), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.user_data_shared", "false"), ), @@ -267,6 +422,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "analytics_configuration.0.application_id", pinpointResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", clientName), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.user_data_shared", "true"), ), @@ -287,6 +443,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfigWithArn(t *testing.T) { testAccPreCheckAWSCognitoIdentityProvider(t) testAccPreCheckAWSPinpointApp(t) }, + ErrorCheck: testAccErrorCheckSkipCognito(t), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ @@ -325,7 +482,7 @@ func TestAccAWSCognitoUserPoolClient_disappears(t *testing.T) { Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - testAccCheckAWSCognitoUserPoolClientDisappears(&client), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPoolClient(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -333,6 +490,35 @@ func TestAccAWSCognitoUserPoolClient_disappears(t *testing.T) { }) } +func TestAccAWSCognitoUserPoolClient_disappears_userPool(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) + clientName := acctest.RandString(10) + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPool(), "aws_cognito_user_pool.test"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccErrorCheckSkipCognito(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "not supported in this region", + ) +} + func testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] @@ -418,21 +604,6 @@ func testAccCheckAWSCognitoUserPoolClientExists(name string, client *cognitoiden } } -func testAccCheckAWSCognitoUserPoolClientDisappears(client *cognitoidentityprovider.UserPoolClientType) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).cognitoidpconn - - params := &cognitoidentityprovider.DeleteUserPoolClientInput{ - ClientId: client.ClientId, - UserPoolId: client.UserPoolId, - } - - _, err := conn.DeleteUserPoolClient(params) - - return err - } -} - func testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { @@ -461,6 +632,73 @@ resource "aws_cognito_user_pool_client" "test" { `, rName, rName, refreshTokenValidity) } +func testAccAWSCognitoUserPoolClientConfigAccessTokenValidity(rName string, validity int) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = "%s" +} + +resource "aws_cognito_user_pool_client" "test" { + name = "%s" + access_token_validity = %d + user_pool_id = aws_cognito_user_pool.test.id +} +`, rName, rName, validity) +} + +func testAccAWSCognitoUserPoolClientConfigIDTokenValidity(rName string, validity int) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = "%s" +} + +resource "aws_cognito_user_pool_client" "test" { + name = "%s" + id_token_validity = %d + user_pool_id = aws_cognito_user_pool.test.id +} +`, rName, rName, validity) +} + +func testAccAWSCognitoUserPoolClientConfigTokenValidityUnits(rName, units string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[1]q + user_pool_id = aws_cognito_user_pool.test.id + + token_validity_units { + access_token = %[2]q + id_token = %[2]q + refresh_token = %[2]q + } +} +`, rName, units) +} + +func testAccAWSCognitoUserPoolClientConfigTokenValidityUnitsWithTokenValidity(rName, units string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[1]q + user_pool_id = aws_cognito_user_pool.test.id + id_token_validity = 1 + + token_validity_units { + access_token = %[2]q + id_token = %[2]q + refresh_token = %[2]q + } +} +`, rName, units) +} + func testAccAWSCognitoUserPoolClientConfig_Name(rName, name string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 4f4b941ff8b..1b0aa2d6097 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -6,6 +6,7 @@ import ( "log" "os" "regexp" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -215,6 +216,7 @@ func TestAccAWSCognitoUserPool_withAdvancedSecurityMode(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheckSkipCognito(t), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ @@ -720,21 +722,15 @@ func TestAccAWSCognitoUserPool_SmsVerificationMessage(t *testing.T) { func TestAccAWSCognitoUserPool_withEmailConfiguration(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - replyTo := fmt.Sprintf("tf-acc-reply-%s@terraformtesting.com", rName) resourceName := "aws_cognito_user_pool.test" - sourceARN, ok := os.LookupEnv("TEST_AWS_SES_VERIFIED_EMAIL_ARN") - if !ok { - t.Skip("'TEST_AWS_SES_VERIFIED_EMAIL_ARN' not set, skipping test.") - } - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolConfig_withEmailConfiguration(rName, "", "", "", "COGNITO_DEFAULT"), + Config: testAccAWSCognitoUserPoolConfig_withEmailConfiguration(rName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "email_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "email_configuration.0.reply_to_email_address", ""), @@ -747,14 +743,36 @@ func TestAccAWSCognitoUserPool_withEmailConfiguration(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func TestAccAWSCognitoUserPool_withEmailConfigurationSource(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + replyTo := fmt.Sprintf("tf-acc-reply-%s@terraformtesting.com", rName) + resourceName := "aws_cognito_user_pool.test" + resourceName2 := "aws_ses_configuration_set.test" + + sourceARN, ok := os.LookupEnv("TEST_AWS_SES_VERIFIED_EMAIL_ARN") + if !ok { + t.Skip("'TEST_AWS_SES_VERIFIED_EMAIL_ARN' not set, skipping test.") + } + emailTo := sourceARN[strings.LastIndex(sourceARN, "/")+1:] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolConfig_withEmailConfiguration(rName, replyTo, sourceARN, "John Smith ", "DEVELOPER"), + Config: testAccAWSCognitoUserPoolConfig_withEmailConfigurationSource(rName, replyTo, sourceARN, emailTo, "DEVELOPER"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "email_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "email_configuration.0.reply_to_email_address", replyTo), resource.TestCheckResourceAttr(resourceName, "email_configuration.0.email_sending_account", "DEVELOPER"), resource.TestCheckResourceAttr(resourceName, "email_configuration.0.source_arn", sourceARN), - resource.TestCheckResourceAttr(resourceName, "email_configuration.0.from_email_address", "John Smith "), + resource.TestCheckResourceAttr(resourceName, "email_configuration.0.from_email_address", emailTo), + resource.TestCheckResourceAttrPair(resourceName, "email_configuration.0.configuration_set", resourceName2, "name"), ), }, }, @@ -1594,8 +1612,28 @@ resource "aws_cognito_user_pool" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccAWSCognitoUserPoolConfig_withEmailConfiguration(rName, email, arn, from, account string) string { +func testAccAWSCognitoUserPoolConfig_withEmailConfiguration(rName string) string { return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q + + email_configuration { + email_sending_account = "COGNITO_DEFAULT" + } +} +`, rName) +} + +func testAccAWSCognitoUserPoolConfig_withEmailConfigurationSource(rName, email, arn, from, account string) string { + return fmt.Sprintf(` +resource "aws_ses_configuration_set" "test" { + name = %[1]q + + delivery_options { + tls_policy = "Optional" + } +} + resource "aws_cognito_user_pool" "test" { name = %[1]q @@ -1604,6 +1642,7 @@ resource "aws_cognito_user_pool" "test" { source_arn = %[3]q from_email_address = %[4]q email_sending_account = %[5]q + configuration_set = aws_ses_configuration_set.test.name } } `, rName, email, arn, from, account) diff --git a/aws/structure.go b/aws/structure.go index dca6f400f6d..712ef92b2f1 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2370,6 +2370,10 @@ func flattenCognitoUserPoolEmailConfiguration(s *cognitoidentityprovider.EmailCo m["email_sending_account"] = *s.EmailSendingAccount } + if s.ConfigurationSet != nil { + m["configuration_set"] = *s.ConfigurationSet + } + if len(m) > 0 { return []map[string]interface{}{m} } diff --git a/aws/validators.go b/aws/validators.go index d5c20782d5d..47967a095ec 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -1849,22 +1849,6 @@ func validateCognitoUserPoolSchemaName(v interface{}, k string) (ws []string, es return } -func validateCognitoUserPoolClientURL(v interface{}, k string) (ws []string, es []error) { - value := v.(string) - if len(value) < 1 { - es = append(es, fmt.Errorf("%q cannot be less than 1 character", k)) - } - - if len(value) > 1024 { - es = append(es, fmt.Errorf("%q cannot be longer than 1024 character", k)) - } - - if !regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`).MatchString(value) { - es = append(es, fmt.Errorf(`%q must satisfy regular expression pattern: [\p{L}\p{M}\p{S}\p{N}\p{P}]+`, k)) - } - return -} - func validateCognitoResourceServerScopeName(v interface{}, k string) (ws []string, errors []error) { value := v.(string) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index db80695b8ec..3fc8ee879e1 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -62,92 +62,99 @@ resource "aws_cognito_user_pool" "test" { ## Argument Reference -The following arguments are supported: - -* `admin_create_user_config` (Optional) - The configuration for [AdminCreateUser](#admin-create-user-config) requests. -* `alias_attributes` - (Optional) Attributes supported as an alias for this user pool. Possible values: phone_number, email, or preferred_username. Conflicts with `username_attributes`. -* `auto_verified_attributes` - (Optional) The attributes to be auto-verified. Possible values: email, phone_number. -* `device_configuration` (Optional) - The configuration for the [user pool's device tracking](#device-configuration). -* `email_configuration` (Optional) - The [Email Configuration](#email-configuration). -* `name` - (Required) The name of the user pool. -* `email_verification_subject` - (Optional) A string representing the email verification subject. Conflicts with `verification_message_template` configuration block `email_subject` argument. -* `email_verification_message` - (Optional) A string representing the email verification message. Conflicts with `verification_message_template` configuration block `email_message` argument. -* `lambda_config` (Optional) - A container for the AWS [Lambda triggers](#lambda-configuration) associated with the user pool. -* `mfa_configuration` - (Optional) Multi-Factor Authentication (MFA) configuration for the User Pool. Defaults of `OFF`. Valid values: - * `OFF` - MFA tokens are not required. - * `ON` - MFA is required for all users to sign in. Requires at least one of `sms_configuration` or `software_token_mfa_configuration` to be configured. - * `OPTIONAL` - MFA will be required only for individual users who have MFA enabled. Requires at least one of `sms_configuration` or `software_token_mfa_configuration` to be configured. -* `password_policy` (Optional) - A container for information about the [user pool password policy](#password-policy). -* `schema` (Optional) - A container with the [schema attributes](#schema-attributes) of a user pool. Schema attributes from the [standard attribute set](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes) only need to be specified if they are different from the default configuration. Maximum of 50 attributes. -* `sms_authentication_message` - (Optional) A string representing the SMS authentication message. The message must contain the `{####}` placeholder, which will be replaced with the code. -* `sms_configuration` (Optional) - Configuration block for Short Message Service (SMS) settings. Detailed below. These settings apply to SMS user verification and SMS Multi-Factor Authentication (MFA). Due to Cognito API restrictions, the SMS configuration cannot be removed without recreating the Cognito User Pool. For user data safety, this resource will ignore the removal of this configuration by disabling drift detection. To force resource recreation after this configuration has been applied, see the [`taint` command](https://www.terraform.io/docs/commands/taint.html). -* `sms_verification_message` - (Optional) A string representing the SMS verification message. Conflicts with `verification_message_template` configuration block `sms_message` argument. -* `software_token_mfa_configuration` - (Optional) Configuration block for software token Mult-Factor Authentication (MFA) settings. Detailed below. -* `tags` - (Optional) A map 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`. -* `username_configuration` - (Optional) The [Username Configuration](#username-configuration). -* `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. -* `account_recovery_setting` (Optional) - The [account_recovery_setting](#account-recovery-setting) configuration. - -#### Admin Create User Config - -* `allow_admin_create_user_only` (Optional) - Set to True if only the administrator is allowed to create user profiles. Set to False if users can sign themselves up via an app. -* `invite_message_template` (Optional) - The [invite message template structure](#invite-message-template). - -##### Invite Message template - -* `email_message` (Optional) - The message template for email messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively. -* `email_subject` (Optional) - The subject line for email messages. -* `sms_message` (Optional) - The message template for SMS messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively. - -#### Device Configuration - -* `challenge_required_on_new_device` (Optional) - Indicates whether a challenge is required on a new device. Only applicable to a new device. -* `device_only_remembered_on_user_prompt` (Optional) - If true, a device is only remembered on user prompt. - -#### Email Configuration - -* `reply_to_email_address` (Optional) - The REPLY-TO email address. -* `source_arn` (Optional) - The ARN of the SES verified email identity to to use. Required if `email_sending_account` is set to `DEVELOPER`. -* `from_email_address` (Optional) - Sender’s email address or sender’s display name with their email address (e.g. `john@example.com`, `John Smith ` or `\"John Smith Ph.D.\" `). Escaped double quotes are required around display names that contain certain characters as specified in [RFC 5322](https://tools.ietf.org/html/rfc5322). -* `email_sending_account` (Optional) - The email delivery method to use. `COGNITO_DEFAULT` for the default email functionality built into Cognito or `DEVELOPER` to use your Amazon SES configuration. - -#### Lambda Configuration - -* `create_auth_challenge` (Optional) - The ARN of the lambda creating an authentication challenge. -* `custom_message` (Optional) - A custom Message AWS Lambda trigger. -* `define_auth_challenge` (Optional) - Defines the authentication challenge. -* `post_authentication` (Optional) - A post-authentication AWS Lambda trigger. -* `post_confirmation` (Optional) - A post-confirmation AWS Lambda trigger. -* `pre_authentication` (Optional) - A pre-authentication AWS Lambda trigger. -* `pre_sign_up` (Optional) - A pre-registration AWS Lambda trigger. -* `pre_token_generation` (Optional) - Allow to customize identity token claims before token generation. -* `user_migration` (Optional) - The user migration Lambda config type. -* `verify_auth_challenge_response` (Optional) - Verifies the authentication challenge response. - -#### Password Policy - -* `minimum_length` (Optional) - The minimum length of the password policy that you have set. -* `require_lowercase` (Optional) - Whether you have required users to use at least one lowercase letter in their password. -* `require_numbers` (Optional) - Whether you have required users to use at least one number in their password. -* `require_symbols` (Optional) - Whether you have required users to use at least one symbol in their password. -* `require_uppercase` (Optional) - Whether you have required users to use at least one uppercase letter in their password. -* `temporary_password_validity_days` (Optional) - In the password policy you have set, refers to the number of days a temporary password is valid. If the user does not sign-in during this time, their password will need to be reset by an administrator. - -#### Schema Attributes - -~> **NOTE:** When defining an `attribute_data_type` of `String` or `Number`, the respective attribute constraints configuration block (e.g `string_attribute_constraints` or `number_attribute_contraints`) is required to prevent recreation of the Terraform resource. This requirement is true for both standard (e.g. name, email) and custom schema attributes. - -* `attribute_data_type` (Required) - The attribute data type. Must be one of `Boolean`, `Number`, `String`, `DateTime`. -* `developer_only_attribute` (Optional) - Specifies whether the attribute type is developer only. -* `mutable` (Optional) - Specifies whether the attribute can be changed once it has been created. -* `name` (Required) - The name of the attribute. -* `number_attribute_constraints` (Optional) - Specifies the [constraints for an attribute of the number type](#number-attribute-constraints). -* `required` (Optional) - Specifies whether a user pool attribute is required. If the attribute is required and the user does not provide a value, registration or sign-in will fail. -* `string_attribute_constraints` (Optional) -Specifies the [constraints for an attribute of the string type](#string-attribute-constraints). - -##### Defaults for Standard Attributes +The following argument is required: + +* `name` - (Required) Name of the user pool. + +The following arguments are optional: + +* `account_recovery_setting` - (Optional) Configuration block to define which verified available method a user can use to recover their forgotten password. [Detailed below](#account_recovery_setting). +* `admin_create_user_config` - (Optional) Configuration block for creating a new user profile. [Detailed below](#admin_create_user_config). +* `alias_attributes` - (Optional) Attributes supported as an alias for this user pool. Valid values: `phone_number`, `email`, or `preferred_username`. Conflicts with `username_attributes`. +* `auto_verified_attributes` - (Optional) Attributes to be auto-verified. Valid values: `email`, `phone_number`. +* `device_configuration` - (Optional) Configuration block for the user pool's device tracking. [Detailed below](#device_configuration). +* `email_configuration` - (Optional) Configuration block for configuring email. [Detailed below](#email_configuration). +* `email_verification_message` - (Optional) String representing the email verification message. Conflicts with `verification_message_template` configuration block `email_message` argument. +* `email_verification_subject` - (Optional) String representing the email verification subject. Conflicts with `verification_message_template` configuration block `email_subject` argument. +* `lambda_config` - (Optional) Configuration block for the AWS Lambda triggers associated with the user pool. [Detailed below](#lambda_configuration). +* `mfa_configuration` - (Optional) Multi-Factor Authentication (MFA) configuration for the User Pool. Defaults of `OFF`. Valid values are `OFF` (MFA Tokens are not required), `ON` (MFA is required for all users to sign in; requires at least one of `sms_configuration` or `software_token_mfa_configuration` to be configured), or `OPTIONAL` (MFA Will be required only for individual users who have MFA Enabled; requires at least one of `sms_configuration` or `software_token_mfa_configuration` to be configured). +* `password_policy` - (Optional) Configuration blocked for information about the user pool password policy. [Detailed below](#password_policy). +* `schema` - (Optional) Configuration block for the schema attributes of a user pool. [Detailed below](#schema). Schema attributes from the [standard attribute set](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes) only need to be specified if they are different from the default configuration. Maximum of 50 attributes. +* `sms_authentication_message` - (Optional) String representing the SMS authentication message. The Message must contain the `{####}` placeholder, which will be replaced with the code. +* `sms_configuration` - (Optional) Configuration block for Short Message Service (SMS) settings. [Detailed below](#sms_configuration). These settings apply to SMS user verification and SMS Multi-Factor Authentication (MFA). Due to Cognito API restrictions, the SMS configuration cannot be removed without recreating the Cognito User Pool. For user data safety, this resource will ignore the removal of this configuration by disabling drift detection. To force resource recreation after this configuration has been applied, see the [`taint` command](https://www.terraform.io/docs/commands/taint.html). +* `sms_verification_message` - (Optional) String representing the SMS verification message. Conflicts with `verification_message_template` configuration block `sms_message` argument. +* `software_token_mfa_configuration` - (Optional) Configuration block for software token Mult-Factor Authentication (MFA) settings. [Detailed below](#software_token_mfa_configuration). +* `tags` - (Optional) Map of tags to assign to the User Pool. +* `user_pool_add_ons` - (Optional) Configuration block for user pool add-ons to enable user pool advanced security mode features. [Detailed below](#user_pool_add_ons). +* `username_attributes` - (Optional) Whether email addresses or phone numbers can be specified as usernames when a user signs up. Conflicts with `alias_attributes`. +* `username_configuration` - (Optional) Configuration block for username configuration. [Detailed below](#username_configuration). +* `verification_message_template` - (Optional) Configuration block for verification message templates. [Detailed below](#verification_message_template). + +### account_recovery_setting + +* `recovery_mechanism` - (Required) List of Account Recovery Options of the following structure: + * `name` - (Required) Recovery method for a user. Can be of the following: `verified_email`, `verified_phone_number`, and `admin_only`. + * `priority` - (Required) Positive integer specifying priority of a method with 1 being the highest priority. + +### admin_create_user_config + +* `allow_admin_create_user_only` - (Optional) Set to True if only the administrator is allowed to create user profiles. Set to False if users can sign themselves up via an app. +* `invite_message_template` - (Optional) Invite message template structure. [Detailed below](#invite_message_template). + +#### invite_message_template + +* `email_message` - (Optional) Message template for email messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively. +* `email_subject` - (Optional) Subject line for email messages. +* `sms_message` - (Optional) Message template for SMS messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively. + +### device_configuration + +* `challenge_required_on_new_device` - (Optional) Whether a challenge is required on a new device. Only applicable to a new device. +* `device_only_remembered_on_user_prompt` - (Optional) Whether a device is only remembered on user prompt. `false` equates to "Always" remember, `true` is "User Opt In," and not using a `device_configuration` block is "No." + +### email_configuration + +* `configuration_set` - (Optional) Email configuration set name from SES. +* `email_sending_account` - (Optional) Email delivery method to use. `COGNITO_DEFAULT` for the default email functionality built into Cognito or `DEVELOPER` to use your Amazon SES configuration. +* `from_email_address` - (Optional) Sender’s email address or sender’s display name with their email address (e.g. `john@example.com`, `John Smith ` or `\"John Smith Ph.D.\" `). Escaped double quotes are required around display names that contain certain characters as specified in [RFC 5322](https://tools.ietf.org/html/rfc5322). +* `reply_to_email_address` - (Optional) REPLY-TO email address. +* `source_arn` - (Optional) ARN of the SES verified email identity to to use. Required if `email_sending_account` is set to `DEVELOPER`. + +### lambda_config + +* `create_auth_challenge` - (Optional) ARN of the lambda creating an authentication challenge. +* `custom_message` - (Optional) Custom Message AWS Lambda trigger. +* `define_auth_challenge` - (Optional) Defines the authentication challenge. +* `post_authentication` - (Optional) Post-authentication AWS Lambda trigger. +* `post_confirmation` - (Optional) Post-confirmation AWS Lambda trigger. +* `pre_authentication` - (Optional) Pre-authentication AWS Lambda trigger. +* `pre_sign_up` - (Optional) Pre-registration AWS Lambda trigger. +* `pre_token_generation` - (Optional) Allow to customize identity token claims before token generation. +* `user_migration` - (Optional) User migration Lambda config type. +* `verify_auth_challenge_response` - (Optional) Verifies the authentication challenge response. + +### password_policy + +* `minimum_length` - (Optional) Minimum length of the password policy that you have set. +* `require_lowercase` - (Optional) Whether you have required users to use at least one lowercase letter in their password. +* `require_numbers` - (Optional) Whether you have required users to use at least one number in their password. +* `require_symbols` - (Optional) Whether you have required users to use at least one symbol in their password. +* `require_uppercase` - (Optional) Whether you have required users to use at least one uppercase letter in their password. +* `temporary_password_validity_days` - (Optional) In the password policy you have set, refers to the number of days a temporary password is valid. If the user does not sign-in during this time, their password will need to be reset by an administrator. + +### schema + +~> **NOTE:** When defining an `attribute_data_type` of `String` or `Number`, the respective attribute constraints configuration block (e.g `string_attribute_constraints` or `number_attribute_contraints`) is **required** to prevent recreation of the Terraform resource. This requirement is true for both standard (e.g. name, email) and custom schema attributes. + +* `attribute_data_type` - (Required) Attribute data type. Must be one of `Boolean`, `Number`, `String`, `DateTime`. +* `developer_only_attribute` - (Optional) Whether the attribute type is developer only. +* `mutable` - (Optional) Whether the attribute can be changed once it has been created. +* `name` - (Required) Name of the attribute. +* `number_attribute_constraints` - (Required when `attribute_data_type` is `Number`) Configuration block for the constraints for an attribute of the number type. [Detailed below](#number_attribute_constraints). +* `required` - (Optional) Whether a user pool attribute is required. If the attribute is required and the user does not provide a value, registration or sign-in will fail. +* `string_attribute_constraints` - (Required when `attribute_data_type` is `String`) Constraints for an attribute of the string type. [Detailed below](#string_attribute_constraints). + +#### schema: Defaults for Standard Attributes The [standard attributes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes) have the following defaults. Note that attributes which match the default values are not stored in Terraform state when importing. @@ -169,59 +176,54 @@ resource "aws_cognito_user_pool" "example" { } ``` -##### Number Attribute Constraints +#### number_attribute_constraints -* `max_value` (Optional) - The maximum value of an attribute that is of the number data type. -* `min_value` (Optional) - The minimum value of an attribute that is of the number data type. +* `max_value` - (Optional) Maximum value of an attribute that is of the number data type. +* `min_value` - (Optional) Minimum value of an attribute that is of the number data type. -##### String Attribute Constraints +#### string_attribute_constraints -* `max_length` (Optional) - The maximum length of an attribute value of the string type. -* `min_length` (Optional) - The minimum length of an attribute value of the string type. +* `max_length` - (Optional) Maximum length of an attribute value of the string type. +* `min_length` - (Optional) Minimum length of an attribute value of the string type. -#### SMS Configuration +### sms_configuration -* `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. +* `external_id` - (Required) 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) ARN of the Amazon SNS caller. This is usually the IAM role that you've given Cognito permission to assume. -### Software Token MFA Configuration +### software_token_mfa_configuration The following arguments are required in the `software_token_mfa_configuration` configuration block: -* `enabled` - (Required) Boolean whether to enable software token Multi-Factor (MFA) tokens, such as Time-based One-Time Password (TOTP). To disable software token MFA when `sms_configuration` is not present, the `mfa_configuration` argument must be set to `OFF` and the `software_token_mfa_configuration` configuration block must be fully removed. +* `enabled` - (Required) Boolean whether to enable software token Multi-Factor (MFA) tokens, such as Time-based One-Time Password (TOTP). To disable software token MFA When `sms_configuration` is not present, the `mfa_configuration` argument must be set to `OFF` and the `software_token_mfa_configuration` configuration block must be fully removed. -#### Username Configuration +### user_pool_add_ons -* `case_sensitive` (Required) - Specifies whether username case sensitivity will be applied for all users in the user pool through Cognito APIs. +* `advanced_security_mode` - (Required) Mode for advanced security, must be one of `OFF`, `AUDIT` or `ENFORCED`. -#### User Pool Add-ons +### username_configuration -* `advanced_security_mode` (Required) - The mode for advanced security, must be one of `OFF`, `AUDIT` or `ENFORCED`. +* `case_sensitive` - (Required) Whether username case sensitivity will be applied for all users in the user pool through Cognito APIs. -#### Verification Message Template +### 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`. -* `email_message` (Optional) - The email message template. Must contain the `{####}` placeholder. Conflicts with `email_verification_message` argument. -* `email_message_by_link` (Optional) - The email message template for sending a confirmation link to the user, it must contain the `{##Click Here##}` placeholder. -* `email_subject` (Optional) - The subject line for the email message template. Conflicts with `email_verification_subject` argument. -* `email_subject_by_link` (Optional) - The subject line for the email message template for sending a confirmation link to the user. -* `sms_message` (Optional) - The SMS message template. Must contain the `{####}` placeholder. Conflicts with `sms_verification_message` argument. +* `default_email_option` - (Optional) Default email option. Must be either `CONFIRM_WITH_CODE` or `CONFIRM_WITH_LINK`. Defaults to `CONFIRM_WITH_CODE`. +* `email_message` - (Optional) Email message template. Must contain the `{####}` placeholder. Conflicts with `email_verification_message` argument. +* `email_message_by_link` - (Optional) Email message template for sending a confirmation link to the user, it must contain the `{##Click Here##}` placeholder. +* `email_subject` - (Optional) Subject line for the email message template. Conflicts with `email_verification_subject` argument. +* `email_subject_by_link` - (Optional) Subject line for the email message template for sending a confirmation link to the user. +* `sms_message` - (Optional) SMS message template. Must contain the `{####}` placeholder. Conflicts with `sms_verification_message` argument. -### Account Recovery Setting - -* `recovery_mechanism` (Required) - The list of Account Recovery Options of the following structure: - * `name` (Required) - Specifies the recovery method for a user. Can be of the following: `verified_email`, `verified_phone_number`, and `admin_only`. - * `priority` (Required) - A positive integer specifying priority of a method with 1 being the highest priority. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `id` - The id of the user pool. -* `arn` - The ARN of the user pool. -* `endpoint` - The endpoint name of the user pool. Example format: cognito-idp.REGION.amazonaws.com/xxxx_yyyyy -* `creation_date` - The date the user pool was created. -* `last_modified_date` - The date the user pool was last modified. +* `arn` - ARN of the user pool. +* `creation_date` - Date the user pool was created. +* `endpoint` - Endpoint name of the user pool. Example format: `cognito-idp.REGION.amazonaws.com/xxxx_yyyyy` +* `id` - ID of the user pool. +* `last_modified_date` - Date the user pool was last modified. ## Import diff --git a/website/docs/r/cognito_user_pool_client.markdown b/website/docs/r/cognito_user_pool_client.markdown index 5bf5f3347c9..c8b6ec2193e 100644 --- a/website/docs/r/cognito_user_pool_client.markdown +++ b/website/docs/r/cognito_user_pool_client.markdown @@ -112,41 +112,55 @@ resource "aws_cognito_user_pool_client" "test" { ## Argument Reference -The following arguments are supported: +The following arguments are required: -* `allowed_oauth_flows` - (Optional) List of allowed OAuth flows (code, implicit, client_credentials). +* `name` - (Required) Name of the application client. +* `user_pool_id` - (Required) User pool the client belongs to. + +The following arguments are optional: + +* `access_token_validity` - (Optional) Time limit, between 5 minutes and 1 day, after which the access token is no longer valid and cannot be used. This value will be overridden if you have entered a value in `token_validity_units`. * `allowed_oauth_flows_user_pool_client` - (Optional) Whether the client is allowed to follow the OAuth protocol when interacting with Cognito user pools. +* `allowed_oauth_flows` - (Optional) List of allowed OAuth flows (code, implicit, client_credentials). * `allowed_oauth_scopes` - (Optional) List of allowed OAuth scopes (phone, email, openid, profile, and aws.cognito.signin.user.admin). +* `analytics_configuration` - (Optional) Configuration block for Amazon Pinpoint analytics for collecting metrics for this user pool. [Detailed below](#analytics_configuration). * `callback_urls` - (Optional) List of allowed callback URLs for the identity providers. -* `default_redirect_uri` - (Optional) The default redirect URI. Must be in the list of callback URLs. -* `explicit_auth_flows` - (Optional) List of authentication flows (ADMIN_NO_SRP_AUTH, CUSTOM_AUTH_FLOW_ONLY, USER_PASSWORD_AUTH, ALLOW_ADMIN_USER_PASSWORD_AUTH, ALLOW_CUSTOM_AUTH, ALLOW_USER_PASSWORD_AUTH, ALLOW_USER_SRP_AUTH, ALLOW_REFRESH_TOKEN_AUTH). +* `default_redirect_uri` - (Optional) Default redirect URI. Must be in the list of callback URLs. +* `explicit_auth_flows` - (Optional) List of authentication flows (ADMIN_NO_SRP_AUTH, CUSTOM_AUTH_FLOW_ONLY, USER_PASSWORD_AUTH, ALLOW_ADMIN_USER_PASSWORD_AUTH, ALLOW_CUSTOM_AUTH, ALLOW_USER_PASSWORD_AUTH, ALLOW_USER_SRP_AUTH, ALLOW_REFRESH_TOKEN_AUTH). * `generate_secret` - (Optional) Should an application secret be generated. +* `id_token_validity` - (Optional) Time limit, between 5 minutes and 1 day, after which the ID token is no longer valid and cannot be used. This value will be overridden if you have entered a value in `token_validity_units`. * `logout_urls` - (Optional) List of allowed logout URLs for the identity providers. -* `name` - (Required) The name of the application client. * `prevent_user_existence_errors` - (Optional) Choose which errors and responses are returned by Cognito APIs during authentication, account confirmation, and password recovery when the user does not exist in the user pool. When set to `ENABLED` and the user does not exist, authentication returns an error indicating either the username or password was incorrect, and account confirmation and password recovery return a response indicating a code was sent to a simulated destination. When set to `LEGACY`, those APIs will return a `UserNotFoundException` exception if the user does not exist in the user pool. * `read_attributes` - (Optional) List of user pool attributes the application client can read from. -* `refresh_token_validity` - (Optional) The time limit in days refresh tokens are valid for. +* `refresh_token_validity` - (Optional) Time limit in days refresh tokens are valid for. * `supported_identity_providers` - (Optional) List of provider names for the identity providers that are supported on this client. -* `user_pool_id` - (Required) The user pool the client belongs to. +* `token_validity_units` - (Optional) Configuration block for units in which the validity times are represented in. [Detailed below](#token_validity_units). * `write_attributes` - (Optional) List of user pool attributes the application client can write to. -* `analytics_configuration` - (Optional) The Amazon Pinpoint analytics configuration for collecting metrics for this user pool. -### Analytics Configuration +### analytics_configuration Either `application_arn` or `application_id` is required. -* `application_arn` - (Optional) The application ARN for an Amazon Pinpoint application. Conflicts with `external_id` and `role_arn`. -* `application_id` - (Optional) The application ID for an Amazon Pinpoint application. -* `external_id` - (Optional) An ID for the Analytics Configuration. Conflicts with `application_arn`. -* `role_arn` - (Optional) The ARN of an IAM role that authorizes Amazon Cognito to publish events to Amazon Pinpoint analytics. Conflicts with `application_arn`. +* `application_arn` - (Optional) Application ARN for an Amazon Pinpoint application. Conflicts with `external_id` and `role_arn`. +* `application_id` - (Optional) Application ID for an Amazon Pinpoint application. +* `external_id` - (Optional) ID for the Analytics Configuration. Conflicts with `application_arn`. +* `role_arn` - (Optional) ARN of an IAM role that authorizes Amazon Cognito to publish events to Amazon Pinpoint analytics. Conflicts with `application_arn`. * `user_data_shared` (Optional) If set to `true`, Amazon Cognito will include user data in the events it publishes to Amazon Pinpoint analytics. -## Attributes Reference +### token_validity_units + +Valid values for the following arguments are: `seconds`, `minutes`, `hours` or `days`. + +* `access_token` - (Optional) Time unit in for the value in `access_token_validity`, defaults to `hours`. +* `id_token` - (Optional) Time unit in for the value in `id_token_validity`, defaults to `hours`. +* `refresh_token` - (Optional) Time unit in for the value in `refresh_token_validity`, defaults to `days`. + +## Attribute Reference In addition to all arguments above, the following attributes are exported: -* `id` - The id of the user pool client. -* `client_secret` - The client secret of the user pool client. +* `client_secret` - Client secret of the user pool client. +* `id` - ID of the user pool client. ## Import