From ddea819cb9d0dd7918e0f4bbdaa0a2204da7b8b5 Mon Sep 17 00:00:00 2001
From: Arkadius Schuchhardt <34404734+Relativity74205@users.noreply.github.com>
Date: Fri, 25 Oct 2024 16:51:27 +0200
Subject: [PATCH] feat: Add authentication policy resource (#3098)

Added the following resources:
- authentication_policy
- account_authentication_policy_attachment
- user_authentication_policy_attachment

## Test Plan
<!-- detail ways in which this PR has been tested or needs to be tested
-->
* [ ] acceptance tests (have been mostly added; could not be tested
locally due to difficulties with acceptance test setup
<!-- add more below if you think they are relevant -->
* [x] manual tests

## References
<!-- issues documentation links, etc  -->

*
https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2880

---------

Co-authored-by: Arkadius Schuchhardt <schuchhardt@auxmoney.com>
---
 ...ccount_authentication_policy_attachment.md |  35 ++
 docs/resources/authentication_policy.md       |  35 ++
 .../user_authentication_policy_attachment.md  |  39 ++
 .../snowflake_authentication_policy/import.sh |   1 +
 .../resource.tf                               |  19 +
 .../snowflake_network_policy/resource.tf      |   2 +-
 pkg/acceptance/check_destroy.go               |  27 +
 pkg/provider/provider.go                      |  13 +-
 pkg/provider/resources/resources.go           |   1 +
 ...ccount_authentication_policy_attachment.go |  88 +++
 ...ation_policy_attachment_acceptance_test.go |  52 ++
 .../account_password_policy_attachment.go     |   2 +-
 ...sword_policy_attachment_acceptance_test.go |  10 +-
 pkg/resources/authentication_policy.go        | 518 ++++++++++++++++++
 .../authentication_policy_acceptance_test.go  |  78 +++
 .../TestAcc_AuthenticationPolicy/test.tf      |  11 +
 .../TestAcc_AuthenticationPolicy/variables.tf |  35 ++
 .../user_authentication_policy_attachment.go  | 134 +++++
 ...ation_policy_attachment_acceptance_test.go |  74 +++
 .../user_password_policy_attachment.go        |   1 +
 pkg/schemas/authentication_policy.go          |  48 ++
 pkg/schemas/authentication_policy_gen.go      |  61 +++
 pkg/schemas/gen/sdk_show_result_structs.go    |   1 +
 pkg/sdk/authentication_policies_def.go        |  52 +-
 24 files changed, 1325 insertions(+), 12 deletions(-)
 create mode 100644 docs/resources/account_authentication_policy_attachment.md
 create mode 100644 docs/resources/authentication_policy.md
 create mode 100644 docs/resources/user_authentication_policy_attachment.md
 create mode 100644 examples/resources/snowflake_authentication_policy/import.sh
 create mode 100644 examples/resources/snowflake_authentication_policy/resource.tf
 create mode 100644 pkg/resources/account_authentication_policy_attachment.go
 create mode 100644 pkg/resources/account_authentication_policy_attachment_acceptance_test.go
 create mode 100644 pkg/resources/authentication_policy.go
 create mode 100644 pkg/resources/authentication_policy_acceptance_test.go
 create mode 100644 pkg/resources/testdata/TestAcc_AuthenticationPolicy/test.tf
 create mode 100644 pkg/resources/testdata/TestAcc_AuthenticationPolicy/variables.tf
 create mode 100644 pkg/resources/user_authentication_policy_attachment.go
 create mode 100644 pkg/resources/user_authentication_policy_attachment_acceptance_test.go
 create mode 100644 pkg/schemas/authentication_policy.go
 create mode 100644 pkg/schemas/authentication_policy_gen.go

diff --git a/docs/resources/account_authentication_policy_attachment.md b/docs/resources/account_authentication_policy_attachment.md
new file mode 100644
index 0000000000..40a93a5ba1
--- /dev/null
+++ b/docs/resources/account_authentication_policy_attachment.md
@@ -0,0 +1,35 @@
+---
+page_title: "snowflake_account_authentication_policy_attachment Resource - terraform-provider-snowflake"
+subcategory: ""
+description: |-
+  Specifies the authentication policy to use for the current account. To set the authentication policy of a different account, use a provider alias.
+---
+
+# snowflake_account_authentication_policy_attachment (Resource)
+
+Specifies the authentication policy to use for the current account. To set the authentication policy of a different account, use a provider alias.
+
+## Example Usage
+
+```terraform
+resource "snowflake_authentication_policy" "default" {
+  database = "prod"
+  schema   = "security"
+  name     = "default_policy"
+}
+
+resource "snowflake_account_authentication_policy_attachment" "attachment" {
+  authentication_policy = snowflake_authentication_policy.default.fully_qualified_name
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `authentication_policy` (String) Qualified name (`"db"."schema"."policy_name"`) of the authentication policy to apply to the current account.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
diff --git a/docs/resources/authentication_policy.md b/docs/resources/authentication_policy.md
new file mode 100644
index 0000000000..ec117e944c
--- /dev/null
+++ b/docs/resources/authentication_policy.md
@@ -0,0 +1,35 @@
+---
+page_title: "snowflake_authentication_policy Resource - terraform-provider-snowflake"
+subcategory: ""
+description: |-
+  
+---
+
+# snowflake_authentication_policy (Resource)
+
+
+
+
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `database` (String) The database in which to create the authentication policy.
+- `name` (String) Specifies the identifier for the authentication policy.
+- `schema` (String) The schema in which to create the authentication policy.
+
+### Optional
+
+- `authentication_methods` (Set of String) A list of authentication methods that are allowed during login. This parameter accepts one or more of the following values: ALL, SAML, PASSWORD, OAUTH, KEYPAIR.
+- `client_types` (Set of String) A list of clients that can authenticate with Snowflake. If a client tries to connect, and the client is not one of the valid CLIENT_TYPES, then the login attempt fails. Allowed values are ALL, SNOWFLAKE_UI, DRIVERS, SNOWSQL. The CLIENT_TYPES property of an authentication policy is a best effort method to block user logins based on specific clients. It should not be used as the sole control to establish a security boundary.
+- `comment` (String) Specifies a comment for the authentication policy.
+- `mfa_authentication_methods` (Set of String) A list of authentication methods that enforce multi-factor authentication (MFA) during login. Authentication methods not listed in this parameter do not prompt for multi-factor authentication. Allowed values are SAML and PASSWORD.
+- `mfa_enrollment` (String) Determines whether a user must enroll in multi-factor authentication. Allowed values are REQUIRED and OPTIONAL. When REQUIRED is specified, Enforces users to enroll in MFA. If this value is used, then the CLIENT_TYPES parameter must include SNOWFLAKE_UI, because Snowsight is the only place users can enroll in multi-factor authentication (MFA).
+- `security_integrations` (Set of String) A list of security integrations the authentication policy is associated with. This parameter has no effect when SAML or OAUTH are not in the AUTHENTICATION_METHODS list. All values in the SECURITY_INTEGRATIONS list must be compatible with the values in the AUTHENTICATION_METHODS list. For example, if SECURITY_INTEGRATIONS contains a SAML security integration, and AUTHENTICATION_METHODS contains OAUTH, then you cannot create the authentication policy. To allow all security integrations use ALL as parameter.
+
+### Read-Only
+
+- `fully_qualified_name` (String) Fully qualified name of the resource. For more information, see [object name resolution](https://docs.snowflake.com/en/sql-reference/name-resolution).
+- `id` (String) The ID of this resource.
diff --git a/docs/resources/user_authentication_policy_attachment.md b/docs/resources/user_authentication_policy_attachment.md
new file mode 100644
index 0000000000..c4fe77a998
--- /dev/null
+++ b/docs/resources/user_authentication_policy_attachment.md
@@ -0,0 +1,39 @@
+---
+page_title: "snowflake_user_authentication_policy_attachment Resource - terraform-provider-snowflake"
+subcategory: ""
+description: |-
+  Specifies the authentication policy to use for a certain user.
+---
+
+# snowflake_user_authentication_policy_attachment (Resource)
+
+Specifies the authentication policy to use for a certain user.
+
+## Example Usage
+
+```terraform
+resource "snowflake_user" "user" {
+  name = "USER_NAME"
+}
+resource "snowflake_authentication_policy" "ap" {
+  database = "prod"
+  schema   = "security"
+  name     = "default_policy"
+}
+
+resource "snowflake_user_authentication_policy_attachment" "apa" {
+  authentication_policy_name = snowflake_authentication_policy.ap.fully_qualified_name
+  user_name                  = snowflake_user.user.name
+}
+```
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `authentication_policy_name` (String) Fully qualified name of the authentication policy
+- `user_name` (String) User name of the user you want to attach the authentication policy to
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
diff --git a/examples/resources/snowflake_authentication_policy/import.sh b/examples/resources/snowflake_authentication_policy/import.sh
new file mode 100644
index 0000000000..81ffd621e8
--- /dev/null
+++ b/examples/resources/snowflake_authentication_policy/import.sh
@@ -0,0 +1 @@
+terraform import snowflake_authentication_policy.example '"<database_name>"."<schema_name>"."<authentication_policy_name>"'
diff --git a/examples/resources/snowflake_authentication_policy/resource.tf b/examples/resources/snowflake_authentication_policy/resource.tf
new file mode 100644
index 0000000000..98745f4fe3
--- /dev/null
+++ b/examples/resources/snowflake_authentication_policy/resource.tf
@@ -0,0 +1,19 @@
+## Minimal
+resource "snowflake_authentication_policy" "basic" {
+  database = "database_name"
+  schema = "schema_name"
+  name = "network_policy_name"
+}
+
+## Complete (with every optional set)
+resource "snowflake_authentication_policy" "complete" {
+  database                   = "database_name"
+  schema                     = "schema_name"
+  name                       = "network_policy_name"
+  authentication_methods     = ["ALL"]
+  mfa_authentication_methods = ["SAML", "PASSWORD"]
+  mfa_enrollment             = "OPTIONAL"
+  client_types               = ["ALL"]
+  security_integrations      = ["ALL"]
+  comment                    = "My authentication policy."
+}
\ No newline at end of file
diff --git a/examples/resources/snowflake_network_policy/resource.tf b/examples/resources/snowflake_network_policy/resource.tf
index 17c0e70fcb..d6cfe4bb62 100644
--- a/examples/resources/snowflake_network_policy/resource.tf
+++ b/examples/resources/snowflake_network_policy/resource.tf
@@ -4,7 +4,7 @@ resource "snowflake_network_policy" "basic" {
 }
 
 ## Complete (with every optional set)
-resource "snowflake_network_policy" "basic" {
+resource "snowflake_network_policy" "complete" {
   name                      = "network_policy_name"
   allowed_network_rule_list = ["<fully qualified network rule id>"]
   blocked_network_rule_list = ["<fully qualified network rule id>"]
diff --git a/pkg/acceptance/check_destroy.go b/pkg/acceptance/check_destroy.go
index cf1b0612c5..f9fd627104 100644
--- a/pkg/acceptance/check_destroy.go
+++ b/pkg/acceptance/check_destroy.go
@@ -99,6 +99,9 @@ var showByIdFunctions = map[resources.Resource]showByIdFunc{
 	resources.ApiIntegration: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
 		return runShowById(ctx, id, client.ApiIntegrations.ShowByID)
 	},
+	resources.AuthenticationPolicy: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
+		return runShowById(ctx, id, client.AuthenticationPolicies.ShowByID)
+	},
 	resources.CortexSearchService: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
 		return runShowById(ctx, id, client.CortexSearchServices.ShowByID)
 	},
@@ -457,6 +460,30 @@ func CheckUserPasswordPolicyAttachmentDestroy(t *testing.T) func(*terraform.Stat
 	}
 }
 
+// CheckUserAuthenticationPolicyAttachmentDestroy is a custom checks that should be later incorporated into generic CheckDestroy
+func CheckUserAuthenticationPolicyAttachmentDestroy(t *testing.T) func(*terraform.State) error {
+	t.Helper()
+	return func(s *terraform.State) error {
+		for _, rs := range s.RootModule().Resources {
+			if rs.Type != "snowflake_user_authentication_policy_attachment" {
+				continue
+			}
+			policyReferences, err := TestClient().PolicyReferences.GetPolicyReferences(t, sdk.NewAccountObjectIdentifierFromFullyQualifiedName(rs.Primary.Attributes["user_name"]), sdk.PolicyEntityDomainUser)
+			if err != nil {
+				if strings.Contains(err.Error(), "does not exist or not authorized") {
+					// Note: this can happen if the Policy Reference or the User has been deleted as well; in this case, ignore the error
+					continue
+				}
+				return err
+			}
+			if len(policyReferences) > 0 {
+				return fmt.Errorf("user authentication policy attachment %v still exists", policyReferences[0].PolicyName)
+			}
+		}
+		return nil
+	}
+}
+
 func TestAccCheckGrantApplicationRoleDestroy(s *terraform.State) error {
 	client := TestAccProvider.Meta().(*provider.Context).Client
 	for _, rs := range s.RootModule().Resources {
diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go
index 24f5d7f479..9f339632d7 100644
--- a/pkg/provider/provider.go
+++ b/pkg/provider/provider.go
@@ -421,15 +421,17 @@ func Provider() *schema.Provider {
 
 func getResources() map[string]*schema.Resource {
 	return map[string]*schema.Resource{
-		"snowflake_account":                            resources.Account(),
-		"snowflake_account_role":                       resources.AccountRole(),
-		"snowflake_account_password_policy_attachment": resources.AccountPasswordPolicyAttachment(),
-		"snowflake_account_parameter":                  resources.AccountParameter(),
-		"snowflake_alert":                              resources.Alert(),
+		"snowflake_account": resources.Account(),
+		"snowflake_account_authentication_policy_attachment":                     resources.AccountAuthenticationPolicyAttachment(),
+		"snowflake_account_role":                                                 resources.AccountRole(),
+		"snowflake_account_password_policy_attachment":                           resources.AccountPasswordPolicyAttachment(),
+		"snowflake_account_parameter":                                            resources.AccountParameter(),
+		"snowflake_alert":                                                        resources.Alert(),
 		"snowflake_api_authentication_integration_with_authorization_code_grant": resources.ApiAuthenticationIntegrationWithAuthorizationCodeGrant(),
 		"snowflake_api_authentication_integration_with_client_credentials":       resources.ApiAuthenticationIntegrationWithClientCredentials(),
 		"snowflake_api_authentication_integration_with_jwt_bearer":               resources.ApiAuthenticationIntegrationWithJwtBearer(),
 		"snowflake_api_integration":                                              resources.APIIntegration(),
+		"snowflake_authentication_policy":                                        resources.AuthenticationPolicy(),
 		"snowflake_cortex_search_service":                                        resources.CortexSearchService(),
 		"snowflake_database_old":                                                 resources.DatabaseOld(),
 		"snowflake_database":                                                     resources.Database(),
@@ -499,6 +501,7 @@ func getResources() map[string]*schema.Resource {
 		"snowflake_task":                                                         resources.Task(),
 		"snowflake_unsafe_execute":                                               resources.UnsafeExecute(),
 		"snowflake_user":                                                         resources.User(),
+		"snowflake_user_authentication_policy_attachment":                        resources.UserAuthenticationPolicyAttachment(),
 		"snowflake_user_password_policy_attachment":                              resources.UserPasswordPolicyAttachment(),
 		"snowflake_user_public_keys":                                             resources.UserPublicKeys(),
 		"snowflake_view":                                                         resources.View(),
diff --git a/pkg/provider/resources/resources.go b/pkg/provider/resources/resources.go
index 45800bb5b0..2076ccbe21 100644
--- a/pkg/provider/resources/resources.go
+++ b/pkg/provider/resources/resources.go
@@ -10,6 +10,7 @@ const (
 	ApiAuthenticationIntegrationWithClientCredentials      resource = "snowflake_api_authentication_integration_with_client_credentials"
 	ApiAuthenticationIntegrationWithJwtBearer              resource = "snowflake_api_authentication_integration_with_jwt_bearer"
 	ApiIntegration                                         resource = "snowflake_api_integration"
+	AuthenticationPolicy                                   resource = "snowflake_authentication_policy"
 	CortexSearchService                                    resource = "snowflake_cortex_search_service"
 	DatabaseOld                                            resource = "snowflake_database_old"
 	Database                                               resource = "snowflake_database"
diff --git a/pkg/resources/account_authentication_policy_attachment.go b/pkg/resources/account_authentication_policy_attachment.go
new file mode 100644
index 0000000000..628cee492c
--- /dev/null
+++ b/pkg/resources/account_authentication_policy_attachment.go
@@ -0,0 +1,88 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider"
+
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+var accountAuthenticationPolicyAttachmentSchema = map[string]*schema.Schema{
+	"authentication_policy": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		Description:      "Qualified name (`\"db\".\"schema\".\"policy_name\"`) of the authentication policy to apply to the current account.",
+		ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](),
+	},
+}
+
+// AccountAuthenticationPolicyAttachment returns a pointer to the resource representing an account authentication policy attachment.
+func AccountAuthenticationPolicyAttachment() *schema.Resource {
+	return &schema.Resource{
+		Description: "Specifies the authentication policy to use for the current account. To set the authentication policy of a different account, use a provider alias.",
+
+		Create: CreateAccountAuthenticationPolicyAttachment,
+		Read:   ReadAccountAuthenticationPolicyAttachment,
+		Delete: DeleteAccountAuthenticationPolicyAttachment,
+
+		Schema: accountAuthenticationPolicyAttachmentSchema,
+		Importer: &schema.ResourceImporter{
+			StateContext: schema.ImportStatePassthroughContext,
+		},
+	}
+}
+
+// CreateAccountAuthenticationPolicyAttachment implements schema.CreateFunc.
+func CreateAccountAuthenticationPolicyAttachment(d *schema.ResourceData, meta interface{}) error {
+	client := meta.(*provider.Context).Client
+	ctx := context.Background()
+
+	authenticationPolicy, ok := sdk.NewObjectIdentifierFromFullyQualifiedName(d.Get("authentication_policy").(string)).(sdk.SchemaObjectIdentifier)
+	if !ok {
+		return fmt.Errorf("authentication_policy %s is not a valid authentication policy qualified name, expected format: `\"db\".\"schema\".\"policy\"`", d.Get("authentication_policy"))
+	}
+
+	err := client.Accounts.Alter(ctx, &sdk.AlterAccountOptions{
+		Set: &sdk.AccountSet{
+			AuthenticationPolicy: authenticationPolicy,
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	d.SetId(helpers.EncodeSnowflakeID(authenticationPolicy))
+
+	return ReadAccountAuthenticationPolicyAttachment(d, meta)
+}
+
+func ReadAccountAuthenticationPolicyAttachment(d *schema.ResourceData, meta interface{}) error {
+	authenticationPolicy := helpers.DecodeSnowflakeID(d.Id())
+	if err := d.Set("authentication_policy", authenticationPolicy.FullyQualifiedName()); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// DeleteAccountAuthenticationPolicyAttachment implements schema.DeleteFunc.
+func DeleteAccountAuthenticationPolicyAttachment(d *schema.ResourceData, meta interface{}) error {
+	client := meta.(*provider.Context).Client
+	ctx := context.Background()
+
+	err := client.Accounts.Alter(ctx, &sdk.AlterAccountOptions{
+		Unset: &sdk.AccountUnset{
+			AuthenticationPolicy: sdk.Bool(true),
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/pkg/resources/account_authentication_policy_attachment_acceptance_test.go b/pkg/resources/account_authentication_policy_attachment_acceptance_test.go
new file mode 100644
index 0000000000..2ef5a658a4
--- /dev/null
+++ b/pkg/resources/account_authentication_policy_attachment_acceptance_test.go
@@ -0,0 +1,52 @@
+package resources_test
+
+import (
+	"fmt"
+	"testing"
+
+	acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/tfversion"
+)
+
+func TestAcc_AccountAuthenticationPolicyAttachment(t *testing.T) {
+	policyName := acc.TestClient().Ids.Alpha()
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+		PreCheck:                 func() { acc.TestAccPreCheck(t) },
+		TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+			tfversion.RequireAbove(tfversion.Version1_5_0),
+		},
+		CheckDestroy: nil,
+		Steps: []resource.TestStep{
+			{
+				Config: accountAuthenticationPolicyAttachmentConfig(acc.TestDatabaseName, acc.TestSchemaName, policyName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrSet("snowflake_account_authentication_policy_attachment.att", "id"),
+				),
+			},
+			{
+				ResourceName:      "snowflake_account_authentication_policy_attachment.att",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func accountAuthenticationPolicyAttachmentConfig(databaseName, schemaName, policyName string) string {
+	s := `
+resource "snowflake_authentication_policy" "pa" {
+	database   = "%s"
+	schema     = "%s"
+	name       = "%v"
+}
+
+resource "snowflake_account_authentication_policy_attachment" "att" {
+	authentication_policy = snowflake_authentication_policy.pa.fully_qualified_name
+}
+`
+	return fmt.Sprintf(s, databaseName, schemaName, policyName)
+}
diff --git a/pkg/resources/account_password_policy_attachment.go b/pkg/resources/account_password_policy_attachment.go
index f362ff1629..245b2d33c2 100644
--- a/pkg/resources/account_password_policy_attachment.go
+++ b/pkg/resources/account_password_policy_attachment.go
@@ -21,7 +21,7 @@ var accountPasswordPolicyAttachmentSchema = map[string]*schema.Schema{
 	},
 }
 
-// AccountPasswordPolicyAttachment returns a pointer to the resource representing an api integration.
+// AccountPasswordPolicyAttachment returns a pointer to the resource representing an account password policy attachment.
 func AccountPasswordPolicyAttachment() *schema.Resource {
 	return &schema.Resource{
 		Description: "Specifies the password policy to use for the current account. To set the password policy of a different account, use a provider alias.",
diff --git a/pkg/resources/account_password_policy_attachment_acceptance_test.go b/pkg/resources/account_password_policy_attachment_acceptance_test.go
index dc43401416..fa42811b22 100644
--- a/pkg/resources/account_password_policy_attachment_acceptance_test.go
+++ b/pkg/resources/account_password_policy_attachment_acceptance_test.go
@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"testing"
 
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+
 	acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
 
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
@@ -11,7 +13,7 @@ import (
 )
 
 func TestAcc_AccountPasswordPolicyAttachment(t *testing.T) {
-	prefix := acc.TestClient().Ids.Alpha()
+	id := acc.TestClient().Ids.RandomSchemaObjectIdentifier()
 
 	resource.Test(t, resource.TestCase{
 		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
@@ -22,7 +24,7 @@ func TestAcc_AccountPasswordPolicyAttachment(t *testing.T) {
 		CheckDestroy: nil,
 		Steps: []resource.TestStep{
 			{
-				Config: accountPasswordPolicyAttachmentConfig(acc.TestDatabaseName, acc.TestSchemaName, prefix),
+				Config: accountPasswordPolicyAttachmentConfig(id),
 				Check: resource.ComposeTestCheckFunc(
 					resource.TestCheckResourceAttrSet("snowflake_account_password_policy_attachment.att", "id"),
 				),
@@ -44,7 +46,7 @@ func TestAcc_AccountPasswordPolicyAttachment(t *testing.T) {
 	})
 }
 
-func accountPasswordPolicyAttachmentConfig(databaseName, schemaName, prefix string) string {
+func accountPasswordPolicyAttachmentConfig(id sdk.SchemaObjectIdentifier) string {
 	s := `
 resource "snowflake_password_policy" "pa" {
 	database   = "%s"
@@ -56,5 +58,5 @@ resource "snowflake_account_password_policy_attachment" "att" {
 	password_policy = snowflake_password_policy.pa.fully_qualified_name
 }
 `
-	return fmt.Sprintf(s, databaseName, schemaName, prefix)
+	return fmt.Sprintf(s, id.DatabaseName(), id.SchemaName(), id.Name())
 }
diff --git a/pkg/resources/authentication_policy.go b/pkg/resources/authentication_policy.go
new file mode 100644
index 0000000000..9dbdff1098
--- /dev/null
+++ b/pkg/resources/authentication_policy.go
@@ -0,0 +1,518 @@
+package resources
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+	"reflect"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+var authenticationPolicySchema = map[string]*schema.Schema{
+	"name": {
+		Type:             schema.TypeString,
+		Required:         true,
+		Description:      blocklistedCharactersFieldDescription("Specifies the identifier for the authentication policy."),
+		DiffSuppressFunc: suppressIdentifierQuoting,
+	},
+	"schema": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		Description:      blocklistedCharactersFieldDescription("The schema in which to create the authentication policy."),
+		DiffSuppressFunc: suppressIdentifierQuoting,
+	},
+	"database": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		Description:      blocklistedCharactersFieldDescription("The database in which to create the authentication policy."),
+		DiffSuppressFunc: suppressIdentifierQuoting,
+	},
+	"authentication_methods": {
+		Type: schema.TypeSet,
+		Elem: &schema.Schema{
+			Type:             schema.TypeString,
+			ValidateDiagFunc: sdkValidation(sdk.ToAuthenticationMethodsOption),
+		},
+		Optional:    true,
+		Description: fmt.Sprintf("A list of authentication methods that are allowed during login. This parameter accepts one or more of the following values: %s", possibleValuesListed(sdk.AllAuthenticationMethods)),
+	},
+	"mfa_authentication_methods": {
+		Type: schema.TypeSet,
+		Elem: &schema.Schema{
+			Type:             schema.TypeString,
+			ValidateDiagFunc: sdkValidation(sdk.ToMfaAuthenticationMethodsOption),
+		},
+		Optional:    true,
+		Description: fmt.Sprintf("A list of authentication methods that enforce multi-factor authentication (MFA) during login. Authentication methods not listed in this parameter do not prompt for multi-factor authentication. Allowed values are %s.", possibleValuesListed(sdk.AllMfaAuthenticationMethods)),
+	},
+	"mfa_enrollment": {
+		Type:             schema.TypeString,
+		Optional:         true,
+		Description:      "Determines whether a user must enroll in multi-factor authentication. Allowed values are REQUIRED and OPTIONAL. When REQUIRED is specified, Enforces users to enroll in MFA. If this value is used, then the CLIENT_TYPES parameter must include SNOWFLAKE_UI, because Snowsight is the only place users can enroll in multi-factor authentication (MFA).",
+		ValidateDiagFunc: sdkValidation(sdk.ToMfaEnrollmentOption),
+		Default:          "OPTIONAL",
+	},
+	"client_types": {
+		Type: schema.TypeSet,
+		Elem: &schema.Schema{
+			Type:             schema.TypeString,
+			ValidateDiagFunc: sdkValidation(sdk.ToClientTypesOption),
+		},
+		Optional:    true,
+		Description: fmt.Sprintf("A list of clients that can authenticate with Snowflake. If a client tries to connect, and the client is not one of the valid CLIENT_TYPES, then the login attempt fails. Allowed values are %s. The CLIENT_TYPES property of an authentication policy is a best effort method to block user logins based on specific clients. It should not be used as the sole control to establish a security boundary.", possibleValuesListed(sdk.AllClientTypes)),
+	},
+	"security_integrations": {
+		Type: schema.TypeSet,
+		Elem: &schema.Schema{
+			Type:             schema.TypeString,
+			ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+		},
+		Optional:    true,
+		Description: "A list of security integrations the authentication policy is associated with. This parameter has no effect when SAML or OAUTH are not in the AUTHENTICATION_METHODS list. All values in the SECURITY_INTEGRATIONS list must be compatible with the values in the AUTHENTICATION_METHODS list. For example, if SECURITY_INTEGRATIONS contains a SAML security integration, and AUTHENTICATION_METHODS contains OAUTH, then you cannot create the authentication policy. To allow all security integrations use ALL as parameter.",
+	},
+	"comment": {
+		Type:        schema.TypeString,
+		Optional:    true,
+		Description: "Specifies a comment for the authentication policy.",
+	},
+	ShowOutputAttributeName: {
+		Type:        schema.TypeList,
+		Computed:    true,
+		Description: "Outputs the result of `SHOW AUTHENTICATION POLICIES` for the given policy.",
+		Elem: &schema.Resource{
+			Schema: schemas.ShowAuthenticationPolicySchema,
+		},
+	},
+	DescribeOutputAttributeName: {
+		Type:        schema.TypeList,
+		Computed:    true,
+		Description: "Outputs the result of `DESCRIBE AUTHENTICATION POLICY` for the given policy.",
+		Elem: &schema.Resource{
+			Schema: schemas.AuthenticationPolicyDescribeSchema,
+		},
+	},
+	FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema,
+}
+
+// AuthenticationPolicy returns a pointer to the resource representing an authentication policy.
+func AuthenticationPolicy() *schema.Resource {
+	return &schema.Resource{
+		CreateContext: CreateContextAuthenticationPolicy,
+		ReadContext:   ReadContextAuthenticationPolicy,
+		UpdateContext: UpdateContextAuthenticationPolicy,
+		DeleteContext: DeleteContextAuthenticationPolicy,
+		Description:   "Resource used to manage authentication policy objects. For more information, check [authentication policy documentation](https://docs.snowflake.com/en/sql-reference/sql/create-authentication-policy).",
+
+		Schema: authenticationPolicySchema,
+		Importer: &schema.ResourceImporter{
+			StateContext: ImportAuthenticationPolicy,
+		},
+	}
+}
+
+func ImportAuthenticationPolicy(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {
+	logging.DebugLogger.Printf("[DEBUG] Starting authentication policy import")
+	client := meta.(*provider.Context).Client
+
+	id, err := sdk.ParseSchemaObjectIdentifier(d.Id())
+	if err != nil {
+		return nil, err
+	}
+
+	authenticationPolicy, err := client.AuthenticationPolicies.ShowByID(ctx, id)
+	if err != nil {
+		return nil, err
+	}
+
+	if err = d.Set("name", authenticationPolicy.Name); err != nil {
+		return nil, err
+	}
+	if err = d.Set("database", authenticationPolicy.DatabaseName); err != nil {
+		return nil, err
+	}
+	if err = d.Set("schema", authenticationPolicy.SchemaName); err != nil {
+		return nil, err
+	}
+	if err = d.Set("comment", authenticationPolicy.Comment); err != nil {
+		return nil, err
+	}
+
+	// needed as otherwise the resource will be incorrectly imported when a list-parameter value equals a default value
+	authenticationPolicyDescriptions, err := client.AuthenticationPolicies.Describe(ctx, id)
+	authenticationMethods := getListParameterFromDescribe(authenticationPolicyDescriptions, "AUTHENTICATION_METHODS")
+	if err = d.Set("authentication_methods", authenticationMethods); err != nil {
+		return nil, err
+	}
+	mfaAuthenticationMethods := getListParameterFromDescribe(authenticationPolicyDescriptions, "MFA_AUTHENTICATION_METHODS")
+	if err = d.Set("mfa_authentication_methods", mfaAuthenticationMethods); err != nil {
+		return nil, err
+	}
+	clientTypes := getListParameterFromDescribe(authenticationPolicyDescriptions, "CLIENT_TYPES")
+	if err = d.Set("client_types", clientTypes); err != nil {
+		return nil, err
+	}
+	securityIntegrations := getListParameterFromDescribe(authenticationPolicyDescriptions, "SECURITY_INTEGRATIONS")
+	if err = d.Set("security_integrations", securityIntegrations); err != nil {
+		return nil, err
+	}
+
+	return []*schema.ResourceData{d}, nil
+}
+
+func CreateContextAuthenticationPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+	name := d.Get("name").(string)
+	databaseName := d.Get("database").(string)
+	schemaName := d.Get("schema").(string)
+	id := sdk.NewSchemaObjectIdentifier(databaseName, schemaName, name)
+
+	req := sdk.NewCreateAuthenticationPolicyRequest(id)
+
+	// Set optionals
+	if v, ok := d.GetOk("authentication_methods"); ok {
+		authenticationMethodsRawList := expandStringList(v.(*schema.Set).List())
+		authenticationMethods := make([]sdk.AuthenticationMethods, len(authenticationMethodsRawList))
+		for i, v := range authenticationMethodsRawList {
+			option, err := sdk.ToAuthenticationMethodsOption(v)
+			if err != nil {
+				return diag.FromErr(err)
+			}
+			authenticationMethods[i] = sdk.AuthenticationMethods{Method: *option}
+		}
+		req.WithAuthenticationMethods(authenticationMethods)
+	}
+
+	if v, ok := d.GetOk("mfa_authentication_methods"); ok {
+		mfaAuthenticationMethodsRawList := expandStringList(v.(*schema.Set).List())
+		mfaAuthenticationMethods := make([]sdk.MfaAuthenticationMethods, len(mfaAuthenticationMethodsRawList))
+		for i, v := range mfaAuthenticationMethodsRawList {
+			option, err := sdk.ToMfaAuthenticationMethodsOption(v)
+			if err != nil {
+				return diag.FromErr(err)
+			}
+			mfaAuthenticationMethods[i] = sdk.MfaAuthenticationMethods{Method: *option}
+		}
+		req.WithMfaAuthenticationMethods(mfaAuthenticationMethods)
+	}
+
+	if v, ok := d.GetOk("mfa_enrollment"); ok {
+		option, err := sdk.ToMfaEnrollmentOption(v.(string))
+		if err != nil {
+			return diag.FromErr(err)
+		}
+		req = req.WithMfaEnrollment(*option)
+	}
+
+	if v, ok := d.GetOk("client_types"); ok {
+		clientTypesRawList := expandStringList(v.(*schema.Set).List())
+		clientTypes := make([]sdk.ClientTypes, len(clientTypesRawList))
+		for i, v := range clientTypesRawList {
+			option, err := sdk.ToClientTypesOption(v)
+			if err != nil {
+				return diag.FromErr(err)
+			}
+			clientTypes[i] = sdk.ClientTypes{ClientType: *option}
+		}
+		req.WithClientTypes(clientTypes)
+	}
+
+	if v, ok := d.GetOk("security_integrations"); ok {
+		securityIntegrationsRawList := expandStringList(v.(*schema.Set).List())
+		securityIntegrations := make([]sdk.SecurityIntegrationsOption, len(securityIntegrationsRawList))
+		for i, v := range securityIntegrationsRawList {
+			securityIntegrations[i] = sdk.SecurityIntegrationsOption{Name: sdk.NewAccountObjectIdentifier(v)}
+		}
+		req.WithSecurityIntegrations(securityIntegrations)
+	}
+
+	if v, ok := d.GetOk("comment"); ok {
+		req = req.WithComment(v.(string))
+	}
+
+	client := meta.(*provider.Context).Client
+	if err := client.AuthenticationPolicies.Create(ctx, req); err != nil {
+		return diag.FromErr(err)
+	}
+	d.SetId(helpers.EncodeResourceIdentifier(id))
+
+	return ReadContextAuthenticationPolicy(ctx, d, meta)
+}
+
+func ReadContextAuthenticationPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+	diags := diag.Diagnostics{}
+	client := meta.(*provider.Context).Client
+	id, err := sdk.ParseSchemaObjectIdentifier(d.Id())
+	if err != nil {
+		return diag.FromErr(err)
+	}
+
+	authenticationPolicy, err := client.AuthenticationPolicies.ShowByID(ctx, id)
+	if err != nil {
+		if errors.Is(err, sdk.ErrObjectNotFound) {
+			d.SetId("")
+			return diag.Diagnostics{
+				diag.Diagnostic{
+					Severity: diag.Warning,
+					Summary:  "Failed to retrieve authentication policy. Target object not found. Marking the resource as removed.",
+					Detail:   fmt.Sprintf("Id: %s", d.Id()),
+				},
+			}
+		}
+		return diag.FromErr(err)
+	}
+
+	authenticationPolicyDescriptions, err := client.AuthenticationPolicies.Describe(ctx, id)
+	if err != nil {
+		return diag.FromErr(err)
+	}
+
+	authenticationMethods := getListArgumentWithDefaults(d, "authentication_methods", getListParameterFromDescribe(authenticationPolicyDescriptions, "AUTHENTICATION_METHODS"), []string{"ALL"})
+	if err = d.Set("authentication_methods", authenticationMethods); err != nil {
+		return diag.FromErr(err)
+	}
+
+	mfaAuthenticationMethods := getListArgumentWithDefaults(d, "mfa_authentication_methods", getListParameterFromDescribe(authenticationPolicyDescriptions, "MFA_AUTHENTICATION_METHODS"), []string{"PASSWORD", "SAML"})
+	if err = d.Set("mfa_authentication_methods", mfaAuthenticationMethods); err != nil {
+		return diag.FromErr(err)
+	}
+
+	mfaEnrollment, err := collections.FindFirst(authenticationPolicyDescriptions, func(prop sdk.AuthenticationPolicyDescription) bool { return prop.Property == "MFA_ENROLLMENT" })
+	if err == nil {
+		if err = d.Set("mfa_enrollment", mfaEnrollment.Value); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+
+	clientTypes := getListArgumentWithDefaults(d, "client_types", getListParameterFromDescribe(authenticationPolicyDescriptions, "CLIENT_TYPES"), []string{"ALL"})
+	if err = d.Set("client_types", clientTypes); err != nil {
+		return diag.FromErr(err)
+	}
+
+	securityIntegrations := getListArgumentWithDefaults(d, "security_integrations", getListParameterFromDescribe(authenticationPolicyDescriptions, "SECURITY_INTEGRATIONS"), []string{"ALL"})
+	if err = d.Set("security_integrations", securityIntegrations); err != nil {
+		return diag.FromErr(err)
+	}
+
+	if err = d.Set("comment", authenticationPolicy.Comment); err != nil {
+		return diag.FromErr(err)
+	}
+	if err := d.Set(FullyQualifiedNameAttributeName, id.FullyQualifiedName()); err != nil {
+		return diag.FromErr(err)
+	}
+
+	if err = d.Set(ShowOutputAttributeName, []map[string]any{schemas.AuthenticationPolicyToSchema(authenticationPolicy)}); err != nil {
+		return diag.FromErr(err)
+	}
+
+	if err = d.Set(DescribeOutputAttributeName, []map[string]any{schemas.AuthenticationPolicyDescriptionToSchema(authenticationPolicyDescriptions)}); err != nil {
+		return diag.FromErr(err)
+	}
+
+	return diags
+}
+
+func getListParameterFromDescribe(authenticationPolicyDescriptions []sdk.AuthenticationPolicyDescription, parameterName string) []string {
+	parameterList := make([]string, 0)
+	if parameterProperty, err := collections.FindFirst(authenticationPolicyDescriptions, func(prop sdk.AuthenticationPolicyDescription) bool {
+		return prop.Property == parameterName
+	}); err == nil {
+		parameterList = append(parameterList, sdk.ParseCommaSeparatedStringArray(parameterProperty.Value, false)...)
+	}
+	return parameterList
+}
+
+// getListArgumentWithDefaults returns the list of values for a given argument, with the defaults applied, if necessary. Otherwise, tf plan will always show a diff with a list parameter with defaults when no value is set.
+func getListArgumentWithDefaults(d *schema.ResourceData, argumentName string, argumentIs []string, argumentDefaults []string) []string {
+	// in case nothing is set in the tf resource and the is equals the default, we set the is to empty
+	argumentShould := d.Get(argumentName).(*schema.Set).List()
+	if stringSlicesEqual(argumentIs, argumentDefaults) && len(argumentShould) == 0 {
+		argumentIs = []string{}
+	}
+	return argumentIs
+}
+
+func UpdateContextAuthenticationPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+	client := meta.(*provider.Context).Client
+	id, err := sdk.ParseSchemaObjectIdentifier(d.Id())
+	if err != nil {
+		return diag.FromErr(err)
+	}
+
+	set, unset := sdk.NewAuthenticationPolicySetRequest(), sdk.NewAuthenticationPolicyUnsetRequest()
+
+	// change to name
+	if d.HasChange("name") {
+		newId, err := sdk.ParseSchemaObjectIdentifier(d.Get("name").(string))
+		if err != nil {
+			return diag.FromErr(err)
+		}
+
+		err = client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(id).WithRenameTo(newId))
+		if err != nil {
+			return diag.FromErr(err)
+		}
+
+		d.SetId(helpers.EncodeResourceIdentifier(newId))
+		id = newId
+	}
+
+	// change to authentication methods
+	if d.HasChange("authentication_methods") {
+		if v, ok := d.GetOk("authentication_methods"); ok {
+			authenticationMethods := expandStringList(v.(*schema.Set).List())
+			authenticationMethodsValues := make([]sdk.AuthenticationMethods, len(authenticationMethods))
+			for i, v := range authenticationMethods {
+				option, err := sdk.ToAuthenticationMethodsOption(v)
+				if err != nil {
+					return diag.FromErr(err)
+				}
+				authenticationMethodsValues[i] = sdk.AuthenticationMethods{Method: *option}
+			}
+
+			set.WithAuthenticationMethods(authenticationMethodsValues)
+		} else {
+			unset.WithAuthenticationMethods(true)
+		}
+	}
+
+	// change to mfa authentication methods
+	if d.HasChange("mfa_authentication_methods") {
+		if v, ok := d.GetOk("mfa_authentication_methods"); ok {
+			mfaAuthenticationMethods := expandStringList(v.(*schema.Set).List())
+			mfaAuthenticationMethodsValues := make([]sdk.MfaAuthenticationMethods, len(mfaAuthenticationMethods))
+			for i, v := range mfaAuthenticationMethods {
+				option, err := sdk.ToMfaAuthenticationMethodsOption(v)
+				if err != nil {
+					return diag.FromErr(err)
+				}
+				mfaAuthenticationMethodsValues[i] = sdk.MfaAuthenticationMethods{Method: *option}
+			}
+
+			set.WithMfaAuthenticationMethods(mfaAuthenticationMethodsValues)
+		} else {
+			unset.WithMfaAuthenticationMethods(true)
+		}
+	}
+
+	// change to mfa enrollment
+	if d.HasChange("mfa_enrollment") {
+		if mfaEnrollmentOption, err := sdk.ToMfaEnrollmentOption(d.Get("mfa_enrollment").(string)); err == nil {
+			set.WithMfaEnrollment(*mfaEnrollmentOption)
+		} else {
+			unset.WithMfaEnrollment(true)
+		}
+	}
+
+	// change to client types
+	if d.HasChange("client_types") {
+		if v, ok := d.GetOk("client_types"); ok {
+			clientTypes := expandStringList(v.(*schema.Set).List())
+			clientTypesValues := make([]sdk.ClientTypes, len(clientTypes))
+			for i, v := range clientTypes {
+				option, err := sdk.ToClientTypesOption(v)
+				if err != nil {
+					return diag.FromErr(err)
+				}
+				clientTypesValues[i] = sdk.ClientTypes{ClientType: *option}
+			}
+
+			set.WithClientTypes(clientTypesValues)
+		} else {
+			unset.WithClientTypes(true)
+		}
+	}
+
+	// change to security integrations
+	if d.HasChange("security_integrations") {
+		if v, ok := d.GetOk("security_integrations"); ok {
+			securityIntegrations := expandStringList(v.(*schema.Set).List())
+			securityIntegrationsValues := make([]sdk.SecurityIntegrationsOption, len(securityIntegrations))
+			for i, v := range securityIntegrations {
+				securityIntegrationsValues[i] = sdk.SecurityIntegrationsOption{Name: sdk.NewAccountObjectIdentifier(v)}
+			}
+
+			set.WithSecurityIntegrations(securityIntegrationsValues)
+		} else {
+			unset.WithSecurityIntegrations(true)
+		}
+	}
+
+	// change to comment
+	if d.HasChange("comment") {
+		if v, ok := d.GetOk("comment"); ok {
+			set.Comment = sdk.String(v.(string))
+		} else {
+			unset.WithComment(true)
+		}
+	}
+
+	if !reflect.DeepEqual(*set, *sdk.NewAuthenticationPolicySetRequest()) {
+		req := sdk.NewAlterAuthenticationPolicyRequest(id).WithSet(*set)
+		if err := client.AuthenticationPolicies.Alter(ctx, req); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+
+	if !reflect.DeepEqual(*unset, *sdk.NewAuthenticationPolicyUnsetRequest()) {
+		req := sdk.NewAlterAuthenticationPolicyRequest(id).WithUnset(*unset)
+		if err := client.AuthenticationPolicies.Alter(ctx, req); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+
+	return ReadContextAuthenticationPolicy(ctx, d, meta)
+}
+
+func DeleteContextAuthenticationPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+	client := meta.(*provider.Context).Client
+	id, err := sdk.ParseSchemaObjectIdentifier(d.Id())
+	if err != nil {
+		return diag.Diagnostics{
+			diag.Diagnostic{
+				Severity: diag.Error,
+				Summary:  "Error deleting authentication policy",
+				Detail:   fmt.Sprintf("id %v err = %v", id.Name(), err),
+			},
+		}
+	}
+
+	if err := client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(id).WithIfExists(true)); err != nil {
+		return diag.FromErr(err)
+	}
+
+	d.SetId("")
+	return nil
+}
+
+func stringSlicesEqual(s1 []string, s2 []string) bool {
+	if len(s1) != len(s2) {
+		return false
+	}
+
+	// convert slices to maps for easy comparison
+	set1 := make(map[string]bool)
+	for _, v := range s1 {
+		set1[v] = true
+	}
+
+	set2 := make(map[string]bool)
+	for _, v := range s2 {
+		set2[v] = true
+	}
+
+	for k, _ := range set1 {
+		if _, ok := set2[k]; !ok {
+			return false
+		}
+	}
+	return true
+}
diff --git a/pkg/resources/authentication_policy_acceptance_test.go b/pkg/resources/authentication_policy_acceptance_test.go
new file mode 100644
index 0000000000..95b7cf7e92
--- /dev/null
+++ b/pkg/resources/authentication_policy_acceptance_test.go
@@ -0,0 +1,78 @@
+package resources_test
+
+import (
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources"
+	"testing"
+
+	acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
+	"github.com/hashicorp/terraform-plugin-testing/config"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/tfversion"
+)
+
+func TestAcc_AuthenticationPolicy(t *testing.T) {
+	accName := acc.TestClient().Ids.Alpha()
+	comment := "This is a test resource"
+	m := func(authenticationMethods []string, mfaAuthenticationMethods []string, mfaEnrollment string, clientTypes []string, securityIntegrations []string) map[string]config.Variable {
+		authenticationMethodsStringVariables := make([]config.Variable, len(authenticationMethods))
+		for i, v := range authenticationMethods {
+			authenticationMethodsStringVariables[i] = config.StringVariable(v)
+		}
+		mfaAuthenticationMethodsStringVariables := make([]config.Variable, len(mfaAuthenticationMethods))
+		for i, v := range mfaAuthenticationMethods {
+			mfaAuthenticationMethodsStringVariables[i] = config.StringVariable(v)
+		}
+		clientTypesStringVariables := make([]config.Variable, len(clientTypes))
+		for i, v := range clientTypes {
+			clientTypesStringVariables[i] = config.StringVariable(v)
+		}
+		securityIntegrationsStringVariables := make([]config.Variable, len(securityIntegrations))
+		for i, v := range securityIntegrations {
+			securityIntegrationsStringVariables[i] = config.StringVariable(v)
+		}
+
+		return map[string]config.Variable{
+			"name":                       config.StringVariable(accName),
+			"database":                   config.StringVariable(acc.TestDatabaseName),
+			"schema":                     config.StringVariable(acc.TestSchemaName),
+			"authentication_methods":     config.SetVariable(authenticationMethodsStringVariables...),
+			"mfa_authentication_methods": config.SetVariable(mfaAuthenticationMethodsStringVariables...),
+			"mfa_enrollment":             config.StringVariable(mfaEnrollment),
+			"client_types":               config.SetVariable(clientTypesStringVariables...),
+			"security_integrations":      config.SetVariable(securityIntegrationsStringVariables...),
+			"comment":                    config.StringVariable(comment),
+		}
+	}
+	variables1 := m([]string{"PASSWORD"}, []string{"PASSWORD"}, "REQUIRED", []string{"SNOWFLAKE_UI"}, []string{"ALL"})
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+		PreCheck:                 func() { acc.TestAccPreCheck(t) },
+		TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+			tfversion.RequireAbove(tfversion.Version1_5_0),
+		},
+		CheckDestroy: acc.CheckDestroy(t, resources.AuthenticationPolicy),
+		Steps: []resource.TestStep{
+			{
+				ConfigDirectory: config.TestNameDirectory(),
+				ConfigVariables: variables1,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "name", accName),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "authentication_methods.0", "PASSWORD"),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "mfa_authentication_methods.0", "PASSWORD"),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "mfa_enrollment", "REQUIRED"),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "client_types.0", "SNOWFLAKE_UI"),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "security_integrations.0", "ALL"),
+					resource.TestCheckResourceAttr("snowflake_authentication_policy.authentication_policy", "comment", comment),
+				),
+			},
+			{
+				ConfigDirectory:   config.TestNameDirectory(),
+				ConfigVariables:   variables1,
+				ResourceName:      "snowflake_authentication_policy.authentication_policy",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
diff --git a/pkg/resources/testdata/TestAcc_AuthenticationPolicy/test.tf b/pkg/resources/testdata/TestAcc_AuthenticationPolicy/test.tf
new file mode 100644
index 0000000000..b78725f2d7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_AuthenticationPolicy/test.tf
@@ -0,0 +1,11 @@
+resource "snowflake_authentication_policy" "authentication_policy" {
+  name                                 = var.name
+  database                             = var.database
+  schema                               = var.schema
+  authentication_methods               = var.authentication_methods
+  mfa_authentication_methods           = var.mfa_authentication_methods
+  mfa_enrollment                       = var.mfa_enrollment
+  client_types                         = var.client_types
+  security_integrations                = var.security_integrations
+  comment                              = var.comment
+}
\ No newline at end of file
diff --git a/pkg/resources/testdata/TestAcc_AuthenticationPolicy/variables.tf b/pkg/resources/testdata/TestAcc_AuthenticationPolicy/variables.tf
new file mode 100644
index 0000000000..4453375033
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_AuthenticationPolicy/variables.tf
@@ -0,0 +1,35 @@
+variable "name" {
+  type = string
+}
+
+variable "database" {
+  type = string
+}
+
+variable "schema" {
+  type = string
+}
+
+variable "authentication_methods" {
+  type = set(string)
+}
+
+variable "mfa_authentication_methods" {
+  type = set(string)
+}
+
+variable "mfa_enrollment" {
+  type = string
+}
+
+variable "client_types" {
+  type = set(string)
+}
+
+variable "security_integrations" {
+  type = set(string)
+}
+
+variable "comment" {
+  type = string
+}
diff --git a/pkg/resources/user_authentication_policy_attachment.go b/pkg/resources/user_authentication_policy_attachment.go
new file mode 100644
index 0000000000..c29b54880f
--- /dev/null
+++ b/pkg/resources/user_authentication_policy_attachment.go
@@ -0,0 +1,134 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider"
+
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+var userAuthenticationPolicyAttachmentSchema = map[string]*schema.Schema{
+	"user_name": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		Description:      "User name of the user you want to attach the authentication policy to",
+		ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+	},
+	"authentication_policy_name": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		Description:      "Fully qualified name of the authentication policy",
+		ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](),
+	},
+}
+
+// UserAuthenticationPolicyAttachment returns a pointer to the resource representing a user authentication policy attachment.
+func UserAuthenticationPolicyAttachment() *schema.Resource {
+	return &schema.Resource{
+		Description: "Specifies the authentication policy to use for a certain user.",
+		Create:      CreateUserAuthenticationPolicyAttachment,
+		Read:        ReadUserAuthenticationPolicyAttachment,
+		Delete:      DeleteUserAuthenticationPolicyAttachment,
+		Schema:      userAuthenticationPolicyAttachmentSchema,
+		Importer: &schema.ResourceImporter{
+			StateContext: schema.ImportStatePassthroughContext,
+		},
+	}
+}
+
+func CreateUserAuthenticationPolicyAttachment(d *schema.ResourceData, meta any) error {
+	client := meta.(*provider.Context).Client
+	ctx := context.Background()
+
+	userName := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(d.Get("user_name").(string))
+	authenticationPolicy := sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(d.Get("authentication_policy_name").(string))
+
+	err := client.Users.Alter(ctx, userName, &sdk.AlterUserOptions{
+		Set: &sdk.UserSet{
+			AuthenticationPolicy: &authenticationPolicy,
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	d.SetId(helpers.EncodeResourceIdentifier(userName.FullyQualifiedName(), authenticationPolicy.FullyQualifiedName()))
+
+	return ReadUserAuthenticationPolicyAttachment(d, meta)
+}
+
+func ReadUserAuthenticationPolicyAttachment(d *schema.ResourceData, meta any) error {
+	client := meta.(*provider.Context).Client
+	ctx := context.Background()
+
+	parts := helpers.ParseResourceIdentifier(d.Id())
+	if len(parts) != 2 {
+		return fmt.Errorf("required id format 'user_name|authentication_policy_name', but got: '%s'", d.Id())
+	}
+
+	// Note: there is no alphanumeric id for an attachment, so we retrieve the authentication policies attached to a certain user.
+	userName := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(parts[0])
+	policyReferences, err := client.PolicyReferences.GetForEntity(ctx, sdk.NewGetForEntityPolicyReferenceRequest(userName, sdk.PolicyEntityDomainUser))
+	if err != nil {
+		return err
+	}
+
+	authenticationPolicyReferences := make([]sdk.PolicyReference, 0)
+	for _, policyReference := range policyReferences {
+		if policyReference.PolicyKind == sdk.PolicyKindAuthenticationPolicy {
+			authenticationPolicyReferences = append(authenticationPolicyReferences, policyReference)
+		}
+	}
+
+	// Note: this should never happen, but just in case: so far, Snowflake only allows one Authentication Policy per user.
+	if len(authenticationPolicyReferences) > 1 {
+		return fmt.Errorf("internal error: multiple policy references attached to a user. This should never happen")
+	}
+
+	// Note: this means the resource has been deleted outside of Terraform.
+	if len(authenticationPolicyReferences) == 0 {
+		d.SetId("")
+		return nil
+	}
+
+	if err := d.Set("user_name", userName.Name()); err != nil {
+		return err
+	}
+	if err := d.Set(
+		"authentication_policy_name",
+		sdk.NewSchemaObjectIdentifier(
+			*authenticationPolicyReferences[0].PolicyDb,
+			*authenticationPolicyReferences[0].PolicySchema,
+			authenticationPolicyReferences[0].PolicyName,
+		).FullyQualifiedName()); err != nil {
+		return err
+	}
+
+	return err
+}
+
+func DeleteUserAuthenticationPolicyAttachment(d *schema.ResourceData, meta any) error {
+	client := meta.(*provider.Context).Client
+	ctx := context.Background()
+
+	userName := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(d.Get("user_name").(string))
+
+	err := client.Users.Alter(ctx, userName, &sdk.AlterUserOptions{
+		Unset: &sdk.UserUnset{
+			AuthenticationPolicy: sdk.Bool(true),
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	d.SetId("")
+
+	return nil
+}
diff --git a/pkg/resources/user_authentication_policy_attachment_acceptance_test.go b/pkg/resources/user_authentication_policy_attachment_acceptance_test.go
new file mode 100644
index 0000000000..99222e2179
--- /dev/null
+++ b/pkg/resources/user_authentication_policy_attachment_acceptance_test.go
@@ -0,0 +1,74 @@
+package resources_test
+
+import (
+	"fmt"
+	"testing"
+
+	acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAcc_UserAuthenticationPolicyAttachment(t *testing.T) {
+	// TODO [SNOW-1423486]: unskip
+	t.Skipf("Skip because error %s; will be fixed in SNOW-1423486", "Error: 000606 (57P03): No active warehouse selected in the current session.  Select an active warehouse with the 'use warehouse' command.")
+	userId := acc.TestClient().Ids.RandomAccountObjectIdentifier()
+	userName := userId.Name()
+	newUserId := acc.TestClient().Ids.RandomAccountObjectIdentifier()
+	newUserName := newUserId.Name()
+	authenticationPolicyId := acc.TestClient().Ids.RandomSchemaObjectIdentifier()
+	authenticationPolicyName := authenticationPolicyId.Name()
+	newAuthenticationPolicyId := acc.TestClient().Ids.RandomSchemaObjectIdentifier()
+	newAuthenticationPolicyName := newAuthenticationPolicyId.Name()
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+		PreCheck:                 func() { acc.TestAccPreCheck(t) },
+		CheckDestroy:             acc.CheckUserAuthenticationPolicyAttachmentDestroy(t),
+		Steps: []resource.TestStep{
+			// CREATE
+			{
+				Config: userAuthenticationPolicyAttachmentConfig(userName, acc.TestDatabaseName, acc.TestSchemaName, authenticationPolicyName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "user_name", userName),
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "authentication_policy_name", authenticationPolicyId.FullyQualifiedName()),
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "id", fmt.Sprintf("%s|%s", userId.FullyQualifiedName(), authenticationPolicyId.FullyQualifiedName())),
+				),
+			},
+			// UPDATE
+			{
+				Config: userAuthenticationPolicyAttachmentConfig(newUserName, acc.TestDatabaseName, acc.TestSchemaName, newAuthenticationPolicyName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "user_name", newUserName),
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "authentication_policy_name", newAuthenticationPolicyId.FullyQualifiedName()),
+					resource.TestCheckResourceAttr("snowflake_user_authentication_policy_attachment.ppa", "id", fmt.Sprintf("%s|%s", userId.FullyQualifiedName(), newAuthenticationPolicyId.FullyQualifiedName())),
+				),
+			},
+			// IMPORT
+			{
+				ResourceName:      "snowflake_user_authentication_policy_attachment.ppa",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func userAuthenticationPolicyAttachmentConfig(userName, databaseName, schemaName, authenticationPolicyName string) string {
+	return fmt.Sprintf(`
+resource "snowflake_user" "user" {
+	name = "%s"
+}
+
+resource "snowflake_authentication_policy" "ap" {
+	database   = "%s"
+	schema     = "%s"
+	name       = "%s"
+}
+
+resource "snowflake_user_authentication_policy_attachment" "apa" {
+	authentication_policy_name = snowflake_authentication_policy.ap.fully_qualified_name
+	user_name = snowflake_user.user.name
+}
+`, userName, databaseName, schemaName, authenticationPolicyName)
+}
diff --git a/pkg/resources/user_password_policy_attachment.go b/pkg/resources/user_password_policy_attachment.go
index 5ec96deebb..96bac9523a 100644
--- a/pkg/resources/user_password_policy_attachment.go
+++ b/pkg/resources/user_password_policy_attachment.go
@@ -28,6 +28,7 @@ var userPasswordPolicyAttachmentSchema = map[string]*schema.Schema{
 	},
 }
 
+// UserPasswordPolicyAttachment returns a pointer to the resource representing a user password policy attachment.
 func UserPasswordPolicyAttachment() *schema.Resource {
 	return &schema.Resource{
 		Description: "Specifies the password policy to use for a certain user.",
diff --git a/pkg/schemas/authentication_policy.go b/pkg/schemas/authentication_policy.go
new file mode 100644
index 0000000000..66b96a5eed
--- /dev/null
+++ b/pkg/schemas/authentication_policy.go
@@ -0,0 +1,48 @@
+package schemas
+
+import (
+	"log"
+	"slices"
+	"strings"
+
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+// AuthenticationPolicyDescribeSchema represents output of DESCRIBE query for the single AuthenticationPolicy.
+var AuthenticationPolicyDescribeSchema = map[string]*schema.Schema{
+	"name":                       {Type: schema.TypeString, Computed: true},
+	"owner":                      {Type: schema.TypeString, Computed: true},
+	"authentication_methods":     {Type: schema.TypeString, Computed: true},
+	"mfa_authentication_methods": {Type: schema.TypeString, Computed: true},
+	"mfa_enrollment":             {Type: schema.TypeString, Computed: true},
+	"client_types":               {Type: schema.TypeString, Computed: true},
+	"security_integrations":      {Type: schema.TypeString, Computed: true},
+	"comment":                    {Type: schema.TypeString, Computed: true},
+}
+
+var _ = AuthenticationPolicyDescribeSchema
+
+var AuthenticationPolicyNames = []string{
+	"NAME",
+	"OWNER",
+	"COMMENT",
+	"AUTHENTICATION_METHODS",
+	"CLIENT_TYPES",
+	"SECURITY_INTEGRATIONS",
+	"MFA_ENROLLMENT",
+	"MFA_AUTHENTICATION_METHODS",
+}
+
+func AuthenticationPolicyDescriptionToSchema(authenticationPolicyDescription []sdk.AuthenticationPolicyDescription) map[string]any {
+	authenticationPolicySchema := make(map[string]any)
+	for _, property := range authenticationPolicyDescription {
+		property := property
+		if slices.Contains(AuthenticationPolicyNames, property.Property) {
+			authenticationPolicySchema[strings.ToLower(property.Property)] = property.Value
+		} else {
+			log.Printf("[WARN] unexpected property %v in authentication policy returned from Snowflake", property.Value)
+		}
+	}
+	return authenticationPolicySchema
+}
diff --git a/pkg/schemas/authentication_policy_gen.go b/pkg/schemas/authentication_policy_gen.go
new file mode 100644
index 0000000000..ed487e4439
--- /dev/null
+++ b/pkg/schemas/authentication_policy_gen.go
@@ -0,0 +1,61 @@
+// Code generated by sdk-to-schema generator; DO NOT EDIT.
+
+package schemas
+
+import (
+	"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+// ShowAuthenticationPolicySchema represents output of SHOW query for the single AuthenticationPolicy.
+var ShowAuthenticationPolicySchema = map[string]*schema.Schema{
+	"created_on": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"name": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"comment": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"database_name": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"schema_name": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"owner": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"owner_role_type": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+	"options": {
+		Type:     schema.TypeString,
+		Computed: true,
+	},
+}
+
+var _ = ShowAuthenticationPolicySchema
+
+func AuthenticationPolicyToSchema(authenticationPolicy *sdk.AuthenticationPolicy) map[string]any {
+	authenticationPolicySchema := make(map[string]any)
+	authenticationPolicySchema["created_on"] = authenticationPolicy.CreatedOn
+	authenticationPolicySchema["name"] = authenticationPolicy.Name
+	authenticationPolicySchema["comment"] = authenticationPolicy.Comment
+	authenticationPolicySchema["database_name"] = authenticationPolicy.DatabaseName
+	authenticationPolicySchema["schema_name"] = authenticationPolicy.SchemaName
+	authenticationPolicySchema["owner"] = authenticationPolicy.Owner
+	authenticationPolicySchema["owner_role_type"] = authenticationPolicy.OwnerRoleType
+	authenticationPolicySchema["options"] = authenticationPolicy.Options
+	return authenticationPolicySchema
+}
+
+var _ = AuthenticationPolicyToSchema
diff --git a/pkg/schemas/gen/sdk_show_result_structs.go b/pkg/schemas/gen/sdk_show_result_structs.go
index 52aaeaa36d..3af846ccc7 100644
--- a/pkg/schemas/gen/sdk_show_result_structs.go
+++ b/pkg/schemas/gen/sdk_show_result_structs.go
@@ -9,6 +9,7 @@ var SdkShowResultStructs = []any{
 	sdk.ApplicationPackage{},
 	sdk.ApplicationRole{},
 	sdk.Application{},
+	sdk.AuthenticationPolicy{},
 	sdk.DatabaseRole{},
 	sdk.Database{},
 	sdk.DynamicTable{},
diff --git a/pkg/sdk/authentication_policies_def.go b/pkg/sdk/authentication_policies_def.go
index 2d283c45dd..1c53e54eeb 100644
--- a/pkg/sdk/authentication_policies_def.go
+++ b/pkg/sdk/authentication_policies_def.go
@@ -1,6 +1,10 @@
 package sdk
 
-import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/generator"
+import (
+	"fmt"
+	g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/generator"
+	"strings"
+)
 
 //go:generate go run ./poc/main.go
 
@@ -185,3 +189,49 @@ var AuthenticationPoliciesDef = g.NewInterface(
 			Name().
 			WithValidation(g.ValidIdentifier, "name"),
 	)
+
+func ToAuthenticationMethodsOption(s string) (*AuthenticationMethodsOption, error) {
+	switch authenticationMethodsOption := AuthenticationMethodsOption(strings.ToUpper(s)); authenticationMethodsOption {
+	case AuthenticationMethodsAll,
+		AuthenticationMethodsSaml,
+		AuthenticationMethodsPassword,
+		AuthenticationMethodsOauth,
+		AuthenticationMethodsKeyPair:
+		return &authenticationMethodsOption, nil
+	default:
+		return nil, fmt.Errorf("invalid authentication method type: %s", s)
+	}
+}
+
+func ToMfaAuthenticationMethodsOption(s string) (*MfaAuthenticationMethodsOption, error) {
+	switch mfaAuthenticationMethodsOption := MfaAuthenticationMethodsOption(strings.ToUpper(s)); mfaAuthenticationMethodsOption {
+	case MfaAuthenticationMethodsAll,
+		MfaAuthenticationMethodsSaml,
+		MfaAuthenticationMethodsPassword:
+		return &mfaAuthenticationMethodsOption, nil
+	default:
+		return nil, fmt.Errorf("invalid MFA authentication method type: %s", s)
+	}
+}
+
+func ToMfaEnrollmentOption(s string) (*MfaEnrollmentOption, error) {
+	switch mfaEnrollmentOption := MfaEnrollmentOption(strings.ToUpper(s)); mfaEnrollmentOption {
+	case MfaEnrollmentRequired,
+		MfaEnrollmentOptional:
+		return &mfaEnrollmentOption, nil
+	default:
+		return nil, fmt.Errorf("invalid enrollment option type: %s", s)
+	}
+}
+
+func ToClientTypesOption(s string) (*ClientTypesOption, error) {
+	switch clientTypesOption := ClientTypesOption(strings.ToUpper(s)); clientTypesOption {
+	case ClientTypesAll,
+		ClientTypesSnowflakeUi,
+		ClientTypesDrivers,
+		ClientTypesSnowSql:
+		return &clientTypesOption, nil
+	default:
+		return nil, fmt.Errorf("invalid client type: %s", s)
+	}
+}