From 3f040a119f63d1a4792a093801596499c2323ab6 Mon Sep 17 00:00:00 2001
From: bohengy <108434983+bohengy@users.noreply.github.com>
Date: Mon, 28 Nov 2022 14:36:04 -0800
Subject: [PATCH] Add new resource WorkforcePoolProvider (#6810)
* test
* Empty entity bug fixed
* First attempt
* First attempt
* completed adding workforce pool provider
* fix bugs
---
.ruby-version | 1 +
mmv1/products/iamworkforcepool/api.yaml | 192 +++++++++++
mmv1/products/iamworkforcepool/terraform.yaml | 47 +++
.../iam_workforce_pool_provider.go.erb | 18 ++
.../iam_workforce_pool.go.erb | 2 +-
..._workforce_pool_provider_oidc_basic.tf.erb | 22 ++
...m_workforce_pool_provider_oidc_full.tf.erb | 26 ++
..._workforce_pool_provider_saml_basic.tf.erb | 21 ++
...m_workforce_pool_provider_saml_full.tf.erb | 25 ++
...ool_workforce_pool_provider_id_test.go.erb | 35 +++
...e_pool_workforce_pool_provider_test.go.erb | 297 ++++++++++++++++++
11 files changed, 685 insertions(+), 1 deletion(-)
create mode 100644 .ruby-version
create mode 100644 mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb
create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb
create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb
create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb
create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb
create mode 100644 mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb
create mode 100644 mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 000000000000..e70b4523ae7f
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+2.6.0
diff --git a/mmv1/products/iamworkforcepool/api.yaml b/mmv1/products/iamworkforcepool/api.yaml
index a278c7a5c487..ec1978ce96b2 100644
--- a/mmv1/products/iamworkforcepool/api.yaml
+++ b/mmv1/products/iamworkforcepool/api.yaml
@@ -126,3 +126,195 @@ objects:
If `sessionDuration` is not configured, minted credentials have a default duration of one hour (3600s).
A duration in seconds with up to nine fractional digits, ending with '`s`'. Example: "`3.5s`".
default_value: '3600s'
+ - !ruby/object:Api::Resource
+ name: 'WorkforcePoolProvider'
+ base_url: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers
+ self_link: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers/{{provider_id}}
+ create_url: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers?workforcePoolProviderId={{provider_id}}
+ update_verb: :PATCH
+ update_mask: true
+ min_version: beta
+ description: |
+ A configuration for an external identity provider.
+ ~> **Note:** Ask your Google Cloud account team to request access to workforce identity
+ federation for your billing/quota project. The account team notifies you when the project is
+ granted access.
+ references: !ruby/object:Api::Resource::ReferenceLinks
+ guides:
+ 'Configure a provider within the workforce pool':
+ 'https://cloud.google.com/iam/docs/manage-workforce-identity-pools-providers#configure_a_provider_within_the_workforce_pool'
+ api: 'https://cloud.google.com/iam/docs/reference/rest/v1/locations.workforcePools.providers'
+ properties:
+ - !ruby/object:Api::Type::String
+ name: 'location'
+ description: The location for the resource.
+ required: true
+ input: true
+ url_param_only: true
+ - !ruby/object:Api::Type::String
+ name: 'workforcePoolId'
+ description: |
+ The ID to use for the pool, which becomes the final component of the resource name.
+ The IDs must be a globally unique string of 6 to 63 lowercase letters, digits, or hyphens.
+ It must start with a letter, and cannot have a trailing hyphen.
+ The prefix `gcp-` is reserved for use by Google, and may not be specified.
+ required: true
+ input: true
+ url_param_only: true
+ - !ruby/object:Api::Type::String
+ name: 'providerId'
+ description: |
+ The ID for the provider, which becomes the final component of the resource name.
+ This value must be 4-32 characters, and may contain the characters [a-z0-9-].
+ The prefix `gcp-` is reserved for use by Google, and may not be specified.
+ required: true
+ input: true
+ url_param_only: true
+ - !ruby/object:Api::Type::String
+ name: 'name'
+ description: |
+ Output only. The resource name of the provider.
+ Format: `locations/{location}/workforcePools/{workforcePoolId}/providers/{providerId}`
+ output: true
+ - !ruby/object:Api::Type::String
+ name: 'displayName'
+ description: A user-specified display name for the provider. Cannot exceed 32 characters.
+ - !ruby/object:Api::Type::String
+ name: 'description'
+ description: A user-specified description of the provider. Cannot exceed 256 characters.
+ - !ruby/object:Api::Type::Enum
+ name: 'state'
+ description: |
+ The current state of the provider.
+ * STATE_UNSPECIFIED: State unspecified.
+ * ACTIVE: The provider is active and may be used to validate authentication credentials.
+ * DELETED: The provider is soft-deleted. Soft-deleted providers are permanently
+ deleted after approximately 30 days. You can restore a soft-deleted provider using
+ [providers.undelete](https://cloud.google.com/iam/docs/reference/rest/v1/locations.workforcePools.providers/undelete#google.iam.admin.v1.WorkforcePools.UndeleteWorkforcePoolProvider).
+ output: true
+ values:
+ - :STATE_UNSPECIFIED
+ - :ACTIVE
+ - :DELETED
+ - !ruby/object:Api::Type::Boolean
+ name: 'disabled'
+ description: |
+ Whether the provider is disabled. You cannot use a disabled provider to exchange tokens.
+ However, existing tokens still grant access.
+ - !ruby/object:Api::Type::KeyValuePairs
+ name: 'attributeMapping'
+ description: |
+ Maps attributes from the authentication credentials issued by an external identity provider
+ to Google Cloud attributes, such as `subject` and `segment`.
+
+ Each key must be a string specifying the Google Cloud IAM attribute to map to.
+
+ The following keys are supported:
+ * `google.subject`: The principal IAM is authenticating. You can reference this value in IAM bindings.
+ This is also the subject that appears in Cloud Logging logs. This is a required field and
+ the mapped subject cannot exceed 127 bytes.
+ * `google.groups`: Groups the authenticating user belongs to. You can grant groups access to
+ resources using an IAM `principalSet` binding; access applies to all members of the group.
+ * `google.display_name`: The name of the authenticated user. This is an optional field and
+ the mapped display name cannot exceed 100 bytes. If not set, `google.subject` will be displayed instead.
+ This attribute cannot be referenced in IAM bindings.
+ * `google.profile_photo`: The URL that specifies the authenticated user's thumbnail photo.
+ This is an optional field. When set, the image will be visible as the user's profile picture.
+ If not set, a generic user icon will be displayed instead.
+ This attribute cannot be referenced in IAM bindings.
+
+ You can also provide custom attributes by specifying `attribute.{custom_attribute}`, where {custom_attribute}
+ is the name of the custom attribute to be mapped. You can define a maximum of 50 custom attributes.
+ The maximum length of a mapped attribute key is 100 characters, and the key may only contain the characters [a-z0-9_].
+
+ You can reference these attributes in IAM policies to define fine-grained access for a workforce pool
+ to Google Cloud resources. For example:
+ * `google.subject`:
+ `principal://iam.googleapis.com/locations/{location}/workforcePools/{pool}/subject/{value}`
+ * `google.groups`:
+ `principalSet://iam.googleapis.com/locations/{location}/workforcePools/{pool}/group/{value}`
+ * `attribute.{custom_attribute}`:
+ `principalSet://iam.googleapis.com/locations/{location}/workforcePools/{pool}/attribute.{custom_attribute}/{value}`
+
+ Each value must be a [Common Expression Language](https://opensource.google/projects/cel)
+ function that maps an identity provider credential to the normalized attribute specified
+ by the corresponding map key.
+
+ You can use the `assertion` keyword in the expression to access a JSON representation of
+ the authentication credential issued by the provider.
+
+ The maximum length of an attribute mapping expression is 2048 characters. When evaluated,
+ the total size of all mapped attributes must not exceed 8KB.
+
+ For OIDC providers, you must supply a custom mapping that includes the `google.subject` attribute.
+ For example, the following maps the sub claim of the incoming credential to the `subject` attribute
+ on a Google token:
+ ```
+ {"google.subject": "assertion.sub"}
+ ```
+
+ An object containing a list of `"key": value` pairs.
+ Example: `{ "name": "wrench", "mass": "1.3kg", "count": "3" }`.
+ - !ruby/object:Api::Type::String
+ name: 'attributeCondition'
+ description: |
+ A [Common Expression Language](https://opensource.google/projects/cel) expression, in
+ plain text, to restrict what otherwise valid authentication credentials issued by the
+ provider should not be accepted.
+
+ The expression must output a boolean representing whether to allow the federation.
+
+ The following keywords may be referenced in the expressions:
+ * `assertion`: JSON representing the authentication credential issued by the provider.
+ * `google`: The Google attributes mapped from the assertion in the `attribute_mappings`.
+ `google.profile_photo` and `google.display_name` are not supported.
+ * `attribute`: The custom attributes mapped from the assertion in the `attribute_mappings`.
+
+ The maximum length of the attribute condition expression is 4096 characters.
+ If unspecified, all valid authentication credentials will be accepted.
+
+ The following example shows how to only allow credentials with a mapped `google.groups` value of `admins`:
+ ```
+ "'admins' in google.groups"
+ ```
+ - !ruby/object:Api::Type::NestedObject
+ name: 'saml'
+ description: Represents a SAML identity provider.
+ exactly_one_of:
+ - saml
+ - oidc
+ properties:
+ - !ruby/object:Api::Type::String
+ name: idpMetadataXml
+ description: |
+ SAML Identity provider configuration metadata xml doc.
+ The xml document should comply with [SAML 2.0 specification](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf).
+ The max size of the acceptable xml document will be bounded to 128k characters.
+
+ The metadata xml document should satisfy the following constraints:
+ 1) Must contain an Identity Provider Entity ID.
+ 2) Must contain at least one non-expired signing key certificate.
+ 3) For each signing key:
+ a) Valid from should be no more than 7 days from now.
+ b) Valid to should be no more than 10 years in the future.
+ 4) Up to 3 IdP signing keys are allowed in the metadata xml.
+
+ When updating the provider's metadata xml, at least one non-expired signing key
+ must overlap with the existing metadata. This requirement is skipped if there are
+ no non-expired signing keys present in the existing metadata.
+ required: true
+ - !ruby/object:Api::Type::NestedObject
+ name: 'oidc'
+ description: Represents an OpenId Connect 1.0 identity provider.
+ exactly_one_of:
+ - saml
+ - oidc
+ properties:
+ - !ruby/object:Api::Type::String
+ name: issuerUri
+ description: The OIDC issuer URI. Must be a valid URI using the 'https' scheme.
+ required: true
+ - !ruby/object:Api::Type::String
+ name: clientId
+ description: The client ID. Must match the audience claim of the JWT issued by the identity provider.
+ required: true
diff --git a/mmv1/products/iamworkforcepool/terraform.yaml b/mmv1/products/iamworkforcepool/terraform.yaml
index 6a1abb8d71b3..4a6c4b261cce 100644
--- a/mmv1/products/iamworkforcepool/terraform.yaml
+++ b/mmv1/products/iamworkforcepool/terraform.yaml
@@ -42,6 +42,53 @@ overrides: !ruby/object:Overrides::ResourceOverrides
workforcePoolId: !ruby/object:Overrides::Terraform::PropertyOverride
validation: !ruby/object:Provider::Terraform::Validation
function: 'validateWorkforcePoolId'
+ WorkforcePoolProvider: !ruby/object:Overrides::Terraform::ResourceOverride
+ autogen_async: true
+ import_format: ["locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers/{{provider_id}}"]
+ examples:
+ - !ruby/object:Provider::Terraform::Examples
+ name: "iam_workforce_pool_provider_saml_basic"
+ min_version: beta
+ primary_resource_id: "example"
+ vars:
+ workforce_pool_id: "example-pool"
+ provider_id: "example-prvdr"
+ test_env_vars:
+ org_id: :ORG_ID
+ - !ruby/object:Provider::Terraform::Examples
+ name: "iam_workforce_pool_provider_saml_full"
+ min_version: beta
+ primary_resource_id: "example"
+ vars:
+ workforce_pool_id: "example-pool"
+ provider_id: "example-prvdr"
+ test_env_vars:
+ org_id: :ORG_ID
+ - !ruby/object:Provider::Terraform::Examples
+ name: "iam_workforce_pool_provider_oidc_basic"
+ min_version: beta
+ primary_resource_id: "example"
+ vars:
+ workforce_pool_id: "example-pool"
+ provider_id: "example-prvdr"
+ test_env_vars:
+ org_id: :ORG_ID
+ - !ruby/object:Provider::Terraform::Examples
+ name: "iam_workforce_pool_provider_oidc_full"
+ min_version: beta
+ primary_resource_id: "example"
+ vars:
+ workforce_pool_id: "example-pool"
+ provider_id: "example-prvdr"
+ test_env_vars:
+ org_id: :ORG_ID
+ custom_code: !ruby/object:Provider::Terraform::CustomCode
+ constants: templates/terraform/constants/iam_workforce_pool_provider.go.erb
+ decoder: templates/terraform/decoders/treat_deleted_state_as_gone.go.erb
+ properties:
+ providerId: !ruby/object:Overrides::Terraform::PropertyOverride
+ validation: !ruby/object:Provider::Terraform::Validation
+ function: 'validateWorkforcePoolProviderId'
# This is for copying files over
files: !ruby/object:Provider::Config::Files
# These files have templating (ERB) code that will be run.
diff --git a/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb b/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb
new file mode 100644
index 000000000000..90d5bb40fa0b
--- /dev/null
+++ b/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb
@@ -0,0 +1,18 @@
+const workforcePoolProviderIdRegexp = `^[a-z0-9-]{4,32}$`
+
+func validateWorkforcePoolProviderId(v interface{}, k string) (ws []string, errors []error) {
+ value := v.(string)
+
+ if strings.HasPrefix(value, "gcp-") {
+ errors = append(errors, fmt.Errorf(
+ "%q \"%q\" can not start with \"gcp-\". " +
+ "The prefix `gcp-` is reserved for use by Google, and may not be specified.", k, value))
+ }
+
+ if !regexp.MustCompile(workforcePoolProviderIdRegexp).MatchString(value) {
+ errors = append(errors, fmt.Errorf(
+ "Workforce Pool Provider Id \"%q\" must be 4-32 characters, and may contain the characters [a-z0-9-].", value))
+ }
+
+ return
+}
diff --git a/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb b/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb
index bd8df83df5b2..f371936e9462 100644
--- a/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb
+++ b/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb
@@ -1,6 +1,6 @@
config := googleProviderConfig(t)
-url, err := replaceVarsForTest(config, rs, "{{IAMBetaBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}")
+url, err := replaceVarsForTest(config, rs, "{{IAMWorkforcePoolBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}")
if err != nil {
return err
}
diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb
new file mode 100644
index 000000000000..72cdae69a79a
--- /dev/null
+++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb
@@ -0,0 +1,22 @@
+resource "google_iam_workforce_pool" "pool" {
+ provider = google-beta
+
+ workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>"
+ parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" {
+ provider = google-beta
+
+ workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id
+ location = google_iam_workforce_pool.pool.location
+ provider_id = "<%= ctx[:vars]["provider_id"] %>"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ oidc {
+ issuer_uri = "https://accounts.google.com"
+ client_id = "client-id"
+ }
+}
diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb
new file mode 100644
index 000000000000..6ff38b004534
--- /dev/null
+++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb
@@ -0,0 +1,26 @@
+resource "google_iam_workforce_pool" "pool" {
+ provider = google-beta
+
+ workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>"
+ parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" {
+ provider = google-beta
+
+ workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id
+ location = google_iam_workforce_pool.pool.location
+ provider_id = "<%= ctx[:vars]["provider_id"] %>"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ oidc {
+ issuer_uri = "https://accounts.google.com"
+ client_id = "client-id"
+ }
+ display_name = "Display name"
+ description = "A sample OIDC workforce pool provider."
+ disabled = false
+ attribute_condition = "true"
+}
diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb
new file mode 100644
index 000000000000..c8853aea29ed
--- /dev/null
+++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb
@@ -0,0 +1,21 @@
+resource "google_iam_workforce_pool" "pool" {
+ provider = google-beta
+
+ workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>"
+ parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" {
+ provider = google-beta
+
+ workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id
+ location = google_iam_workforce_pool.pool.location
+ provider_id = "<%= ctx[:vars]["provider_id"] %>"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ saml {
+ idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv"
+ }
+}
diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb
new file mode 100644
index 000000000000..724f895c994d
--- /dev/null
+++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb
@@ -0,0 +1,25 @@
+resource "google_iam_workforce_pool" "pool" {
+ provider = google-beta
+
+ workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>"
+ parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" {
+ provider = google-beta
+
+ workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id
+ location = google_iam_workforce_pool.pool.location
+ provider_id = "<%= ctx[:vars]["provider_id"] %>"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ saml {
+ idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv"
+ }
+ display_name = "Display name"
+ description = "A sample SAML workforce pool provider."
+ disabled = false
+ attribute_condition = "true"
+}
diff --git a/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb
new file mode 100644
index 000000000000..e10391536ba3
--- /dev/null
+++ b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb
@@ -0,0 +1,35 @@
+<% autogen_exception -%>
+package google
+
+<% unless version == 'ga' -%>
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestValidateIAMWorkforcePoolWorkforcePoolProviderId(t *testing.T) {
+ x := []StringValidationTestCase{
+ // No errors
+ {TestName: "with numbers", Value: "foobar123"},
+ {TestName: "short", Value: "foo-"},
+ {TestName: "long", Value: strings.Repeat("f", 32)},
+ {TestName: "has a hyphen", Value: "foo-bar"},
+
+ // With errors
+ {TestName: "empty", Value: "", ExpectError: true},
+ {TestName: "starts with a gcp-", Value: "gcp-foobar", ExpectError: true},
+ {TestName: "with uppercase", Value: "fooBar", ExpectError: true},
+ {TestName: "has an slash", Value: "foo/bar", ExpectError: true},
+ {TestName: "has an backslash", Value: "foo\bar", ExpectError: true},
+ {TestName: "too short", Value: "foo", ExpectError: true},
+ {TestName: "too long", Value: strings.Repeat("f", 33), ExpectError: true},
+ }
+
+ es := testStringValidationCases(x, validateWorkforcePoolProviderId)
+ if len(es) > 0 {
+ t.Errorf("Failed to validate WorkforcePoolProvider names: %v", es)
+ }
+}
+
+<% end -%>
diff --git a/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb
new file mode 100644
index 000000000000..4055dc45d6b5
--- /dev/null
+++ b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb
@@ -0,0 +1,297 @@
+<% autogen_exception -%>
+package google
+
+<% unless version == 'ga' -%>
+
+import (
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+ "testing"
+)
+
+func TestAccIAMWorkforcePoolWorkforcePoolProvider_oidc(t *testing.T) {
+ t.Parallel()
+
+ random_suffix := randString(t, 10)
+ context := map[string]interface{}{
+ "org_id": getTestOrgFromEnv(t),
+ "random_suffix": random_suffix,
+ }
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckIAMWorkforcePoolWorkforcePoolDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_full(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_update(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_basic(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t, random_suffix),
+ ),
+ },
+ },
+ })
+}
+
+func TestAccIAMWorkforcePoolWorkforcePoolProvider_saml(t *testing.T) {
+ t.Parallel()
+
+ random_suffix := randString(t, 10)
+ context := map[string]interface{}{
+ "org_id": getTestOrgFromEnv(t),
+ "random_suffix": random_suffix,
+ }
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckIAMWorkforcePoolWorkforcePoolDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_full(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_update(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_basic(context),
+ },
+ {
+ ResourceName: "google_iam_workforce_pool_provider.my_provider",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t, random_suffix),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t *testing.T, random_suffix string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ pool_resource_name := "google_iam_workforce_pool.my_pool"
+ pool_rs, ok := s.RootModule().Resources[pool_resource_name]
+ if !ok {
+ return fmt.Errorf("Resource %s Not found", pool_resource_name)
+ }
+ config := googleProviderConfig(t)
+
+ pool_url, err := replaceVarsForTest(config, pool_rs, "{{IAMWorkforcePoolBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}")
+ if err != nil {
+ return err
+ }
+
+ url := fmt.Sprintf("%s/providers/my-provider-%s", pool_url, random_suffix)
+ res, err := sendRequest(config, "GET", "", url, config.userAgent, nil)
+ if err != nil {
+ return nil
+ }
+
+ if v := res["state"]; v == "DELETED" {
+ return nil
+ }
+
+ return fmt.Errorf("IAMWorkforcePoolProvider still exists at %s", url)
+ }
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_full(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ oidc {
+ issuer_uri = "https://accounts.google.com"
+ client_id = "client-id"
+ }
+ display_name = "Display name"
+ description = "A sample OIDC workforce pool provider."
+ disabled = false
+ attribute_condition = "true"
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_update(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject" = "false"
+ }
+ oidc {
+ issuer_uri = "https://test.google.com"
+ client_id = "new-client-id"
+ }
+ display_name = "New Display name"
+ description = "A sample OIDC workforce pool provider with updated description."
+ disabled = true
+ attribute_condition = "false"
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_basic(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ oidc {
+ issuer_uri = "https://accounts.google.com"
+ client_id = "client-id"
+ }
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_full(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ saml {
+ idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv"
+ }
+ display_name = "Display name"
+ description = "A sample SAML workforce pool provider."
+ disabled = false
+ attribute_condition = "true"
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_update(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject": "false"
+ }
+ saml {
+ idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv"
+ }
+ display_name = "New Display name"
+ description = "A sample SAML workforce pool provider with updated description."
+ disabled = true
+ attribute_condition = "false"
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_basic(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+
+resource "google_iam_workforce_pool_provider" "my_provider" {
+ workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id
+ location = google_iam_workforce_pool.my_pool.location
+ provider_id = "my-provider-%{random_suffix}"
+ attribute_mapping = {
+ "google.subject" = "assertion.sub"
+ }
+ saml {
+ idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv"
+ }
+}
+`, context)
+}
+
+func testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context map[string]interface{}) string {
+ return Nprintf(`
+resource "google_iam_workforce_pool" "my_pool" {
+ workforce_pool_id = "my-pool-%{random_suffix}"
+ parent = "organizations/%{org_id}"
+ location = "global"
+}
+`, context)
+}
+<% end -%>