-
Notifications
You must be signed in to change notification settings - Fork 9.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Resource: aws_cognito_identity_provider #3601
Changes from 4 commits
8c52fe1
7756cf2
a8b5a3d
17ac7cc
e0bc329
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceAwsCognitoIdentityProvider() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceAwsCognitoIdentityProviderCreate, | ||
Read: resourceAwsCognitoIdentityProviderRead, | ||
Update: resourceAwsCognitoIdentityProviderUpdate, | ||
Delete: resourceAwsCognitoIdentityProviderDelete, | ||
|
||
Timeouts: &schema.ResourceTimeout{ | ||
Delete: schema.DefaultTimeout(5 * time.Minute), | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"attribute_mapping": { | ||
Type: schema.TypeMap, | ||
Optional: true, | ||
}, | ||
|
||
"idp_identifiers": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
|
||
"provider_details": { | ||
Type: schema.TypeMap, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
|
||
"provider_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"provider_type": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"user_pool_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should user_pool_id be ForceNew? If the pool id changes, wouldn't a new provider need to be created? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsCognitoIdentityProviderCreate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cognitoidpconn | ||
log.Print("[DEBUG] Creating Cognito Identity Provider") | ||
|
||
name := aws.String(d.Get("provider_name").(string)) | ||
params := &cognitoidentityprovider.CreateIdentityProviderInput{ | ||
ProviderName: name, | ||
ProviderType: aws.String(d.Get("provider_type").(string)), | ||
UserPoolId: aws.String(d.Get("user_pool_id").(string)), | ||
} | ||
|
||
if v, ok := d.GetOk("attribute_mapping"); ok { | ||
params.AttributeMapping = expandCognitoIdentityProviderMap(v.(map[string]interface{})) | ||
} | ||
|
||
if v, ok := d.GetOk("provider_details"); ok { | ||
params.ProviderDetails = expandCognitoIdentityProviderMap(v.(map[string]interface{})) | ||
} | ||
|
||
if v, ok := d.GetOk("idp_identifiers"); ok { | ||
params.IdpIdentifiers = expandStringList(v.([]interface{})) | ||
} | ||
|
||
_, err := conn.CreateIdentityProvider(params) | ||
if err != nil { | ||
return fmt.Errorf("Error creating Cognito Identity Provider: %s", err) | ||
} | ||
|
||
d.SetId(*name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to easily support import, let's prepend the resource ID with the user pool ID: d.SetId(fmt.Sprintf("%s:%s", userPoolID, providerName)) Then with configuring the passthrough |
||
|
||
return resourceAwsCognitoIdentityProviderRead(d, meta) | ||
} | ||
|
||
func resourceAwsCognitoIdentityProviderRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cognitoidpconn | ||
log.Printf("[DEBUG] Reading Cognito Identity Provider: %s", d.Id()) | ||
|
||
ret, err := conn.DescribeIdentityProvider(&cognitoidentityprovider.DescribeIdentityProviderInput{ | ||
ProviderName: aws.String(d.Id()), | ||
UserPoolId: aws.String(d.Get("user_pool_id").(string)), | ||
}) | ||
|
||
if err != nil { | ||
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick: we have a helper function to simplify this logic: |
||
d.SetId("") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When removing a resource from the state, we prefer to provide a warning log, e.g. log.Printf("[WARN] Cognito Identity Provider %q not found, removing from state", d.Id()) |
||
return nil | ||
} | ||
return err | ||
} | ||
|
||
ip := ret.IdentityProvider | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should perform a |
||
d.Set("provider_name", ip.ProviderName) | ||
d.Set("provider_type", ip.ProviderType) | ||
d.Set("user_pool_id", ip.UserPoolId) | ||
|
||
if err := d.Set("attribute_mapping", flattenCognitoIdentityProviderMap(ip.AttributeMapping)); err != nil { | ||
return fmt.Errorf("[DEBUG] Error setting attribute_mapping error: %#v", err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick: these error messages will be returned to the operator, so they are not |
||
} | ||
|
||
if err := d.Set("provider_details", flattenCognitoIdentityProviderMap(ip.ProviderDetails)); err != nil { | ||
return fmt.Errorf("[DEBUG] Error setting provider_details error: %#v", err) | ||
} | ||
|
||
if err := d.Set("idp_identifiers", flattenStringList(ip.IdpIdentifiers)); err != nil { | ||
return fmt.Errorf("[DEBUG] Error setting idp_identifiers error: %#v", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsCognitoIdentityProviderUpdate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cognitoidpconn | ||
log.Print("[DEBUG] Updating Cognito Identity Provider") | ||
|
||
params := &cognitoidentityprovider.UpdateIdentityProviderInput{ | ||
UserPoolId: aws.String(d.Get("UserPoolId").(string)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wondering... is "d.Get("UserPoolId") correct? Or should it be: d.Get("user_pool_id")? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I will change it. |
||
ProviderName: aws.String(d.Id()), | ||
} | ||
|
||
if d.HasChange("attribute_mapping") { | ||
params.AttributeMapping = expandCognitoIdentityProviderMap(d.Get("attribute_mapping").(map[string]interface{})) | ||
} | ||
|
||
if d.HasChange("provider_details") { | ||
params.ProviderDetails = expandCognitoIdentityProviderMap(d.Get("provider_details").(map[string]interface{})) | ||
} | ||
|
||
if d.HasChange("idp_identifiers") { | ||
params.IdpIdentifiers = expandStringList(d.Get("supported_login_providers").([]interface{})) | ||
} | ||
|
||
_, err := conn.UpdateIdentityProvider(params) | ||
if err != nil { | ||
return fmt.Errorf("Error updating Cognito Identity Provider: %s", err) | ||
} | ||
|
||
return resourceAwsCognitoIdentityProviderRead(d, meta) | ||
} | ||
|
||
func resourceAwsCognitoIdentityProviderDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).cognitoidpconn | ||
log.Printf("[DEBUG] Deleting Cognito Identity Provider: %s", d.Id()) | ||
|
||
return resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This retry loop looks extraneous as there is no |
||
_, err := conn.DeleteIdentityProvider(&cognitoidentityprovider.DeleteIdentityProviderInput{ | ||
ProviderName: aws.String(d.Id()), | ||
UserPoolId: aws.String(d.Get("user_pool_id").(string)), | ||
}) | ||
|
||
if err == nil { | ||
d.SetId("") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick: |
||
return nil | ||
} | ||
|
||
return resource.NonRetryableError(err) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package aws | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSCognitoIdentityProvider_basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSCognitoIdentityProviderDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSCognitoIdentityProviderConfig_basic(), | ||
Check: resource.ComposeAggregateTestCheckFunc( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is missing an |
||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_name", "Google"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_type", "Google"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.%", "9"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.authorize_scopes", "email"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.authorize_url", "https://accounts.google.com/o/oauth2/v2/auth"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.client_id", "test-url.apps.googleusercontent.com"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.client_secret", "client_secret"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.attributes_url", "https://people.googleapis.com/v1/people/me?personFields="), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.attributes_url_add_attributes", "true"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.token_request_method", "POST"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.token_url", "https://www.googleapis.com/oauth2/v4/token"), | ||
resource.TestCheckResourceAttr("aws_cognito_identity_provider.tf_test_provider", "provider_details.oidc_issuer", "https://accounts.google.com"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAWSCognitoIdentityProviderDestroy(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*AWSClient).cognitoidpconn | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "aws_cognito_identity_provider" { | ||
continue | ||
} | ||
|
||
_, err := conn.DescribeIdentityProvider(&cognitoidentityprovider.DescribeIdentityProviderInput{ | ||
ProviderName: aws.String(rs.Primary.ID), | ||
UserPoolId: aws.String(rs.Primary.Attributes["user_pool_id"]), | ||
}) | ||
|
||
if err != nil { | ||
if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "ResourceNotFoundException" { | ||
return nil | ||
} | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccAWSCognitoIdentityProviderConfig_basic() string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick: the formatting is fairly inconsistent throughout this test configuration which makes it harder to read |
||
return ` | ||
|
||
resource "aws_cognito_user_pool" "tf_test_pool" { | ||
name = "tfmytestpool" | ||
auto_verified_attributes = ["email"] | ||
} | ||
|
||
resource "aws_cognito_identity_provider" "tf_test_provider" { | ||
user_pool_id = "${aws_cognito_user_pool.tf_test_pool.id}" | ||
provider_name = "Google" | ||
provider_type = "Google" | ||
|
||
provider_details { | ||
authorize_scopes = "email" | ||
client_id = "test-url.apps.googleusercontent.com" | ||
client_secret = "client_secret" | ||
attributes_url = "https://people.googleapis.com/v1/people/me?personFields=" | ||
attributes_url_add_attributes = "true" | ||
authorize_url = "https://accounts.google.com/o/oauth2/v2/auth" | ||
oidc_issuer = "https://accounts.google.com" | ||
token_request_method = "POST" | ||
token_url = "https://www.googleapis.com/oauth2/v4/token" | ||
} | ||
|
||
attribute_mapping { | ||
email = "email" | ||
username = "sub" | ||
} | ||
} | ||
` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3035,6 +3035,23 @@ func flattenCognitoIdentityPoolRoles(config map[string]*string) map[string]strin | |
return m | ||
} | ||
|
||
func expandCognitoIdentityProviderMap(config map[string]interface{}) map[string]*string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have a (admittedly hard to find) helper function to perform this already: |
||
m := map[string]*string{} | ||
for k, v := range config { | ||
s := v.(string) | ||
m[k] = &s | ||
} | ||
return m | ||
} | ||
|
||
func flattenCognitoIdentityProviderMap(config map[string]*string) map[string]string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The AWS SDK already provides a helper function to perform this: |
||
m := map[string]string{} | ||
for k, v := range config { | ||
m[k] = *v | ||
} | ||
return m | ||
} | ||
|
||
func expandCognitoIdentityPoolRoleMappingsAttachment(rms []interface{}) map[string]*cognitoidentity.RoleMapping { | ||
values := make(map[string]*cognitoidentity.RoleMapping, 0) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--- | ||
layout: "aws" | ||
page_title: "AWS: aws_cognito_identity_provider" | ||
side_bar_current: "docs-aws-resource-cognito-identity-provider" | ||
description: |- | ||
Provides a Cognito User Identity Provider resource. | ||
--- | ||
|
||
# aws_cognito_identity_provider | ||
|
||
Provides a Cognito User Identity Provider resource. | ||
|
||
## Example Usage | ||
|
||
### Basic configuration | ||
|
||
```hcl | ||
resource "aws_cognito_user_pool" "example" { | ||
name = "example-pool" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick: the formatting is slightly off in the example configuration here and below with email |
||
auto_verified_attributes = ["email"] | ||
} | ||
|
||
resource "aws_cognito_identity_provider" "example_provider" { | ||
user_pool_id = "${aws_cognito_user_pool.example.id}" | ||
provider_name = "example_name" | ||
provider_type = "Google" | ||
|
||
provider_details { | ||
authorize_scopes = "email" | ||
client_id = "your client_id" | ||
client_secret = "your client_secret" | ||
} | ||
|
||
attribute_mapping { | ||
email = "email" | ||
username = "sub" | ||
} | ||
} | ||
``` | ||
|
||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `user_pool_id` (Required) - The user pool id | ||
* `provider_name` (Required) - The provider name | ||
* `provider_type` (Required) - The provider type. [See AWS API for valid values](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateIdentityProvider.html#CognitoUserPools-CreateIdentityProvider-request-ProviderType) | ||
* `attribute_mapping` (Optional) - The map of attribute mapping of user pool attributes. [AttributeMapping in AWS API documentation](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateIdentityProvider.html#CognitoUserPools-CreateIdentityProvider-request-AttributeMapping) | ||
* `idp_identifiers` (Optional) - The list of identity providers. | ||
* `provider_details` (Optional) - The map of identity details, such as access token | ||
|
||
## Timeouts | ||
|
||
`aws_cognito_identity_provider` provides the following | ||
[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: | ||
- `delete` - (Default `5 minutes`) Used for provider deletion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this was intentional, but it does not seem like we should be ignoring this from the API if its not in the Terraform configuration. I'll double check from the acceptance testing. Also, the API/SDK documentation seems to imply this should be
Required: true
.