diff --git a/CHANGELOG.md b/CHANGELOG.md index 25a4563ec..03cc0bc10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ FEATURES: * Add support for new WIF fields in `vault_gcp_auth_backend` ([#2256](https://github.com/hashicorp/terraform-provider-vault/pull/2256)) * Add support for new WIF fields in `vault_azure_auth_backend_config`. Requires Vault 1.17+. *Available only for Vault Enterprise* ([#2254](https://github.com/hashicorp/terraform-provider-vault/pull/2254)). * Add new data source and resource `vault_pki_secret_backend_config_est`. Requires Vault 1.16+. *Available only for Vault Enterprise* ([#2246](https://github.com/hashicorp/terraform-provider-vault/pull/2246)) +* Support missing token parameters on `vault_okta_auth_backend` resource: ([#2210](https://github.com/hashicorp/terraform-provider-vault/pull/2210)) * Add support for `max_retries` in `vault_aws_auth_backend_client`: ([#2270](https://github.com/hashicorp/terraform-provider-vault/pull/2270)) IMPROVEMENTS: diff --git a/internal/consts/consts.go b/internal/consts/consts.go index 8da3e82d8..82b5ca796 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -501,6 +501,7 @@ const ( MountTypeTerraform = "terraform" MountTypeNone = "none" MountTypeSAML = "saml" + MountTypeOkta = "okta" /* Vault version constants diff --git a/vault/resource_okta_auth_backend.go b/vault/resource_okta_auth_backend.go index a98eb3639..ffcf048d4 100644 --- a/vault/resource_okta_auth_backend.go +++ b/vault/resource_okta_auth_backend.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/hashicorp/go-secure-stdlib/parseutil" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/vault/api" @@ -24,199 +25,212 @@ import ( var oktaAuthType = "okta" +const ( + fieldBypassOktaMFA = "bypass_okta_mfa" + fieldUser = "user" + fieldGroup = "group" + fieldGroups = "groups" +) + func oktaAuthBackendResource() *schema.Resource { - return provider.MustAddMountMigrationSchema(&schema.Resource{ - Create: oktaAuthBackendWrite, - Delete: oktaAuthBackendDelete, - Read: provider.ReadWrapper(oktaAuthBackendRead), - Update: oktaAuthBackendUpdate, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - CustomizeDiff: getMountCustomizeDiffFunc(consts.FieldPath), - Schema: map[string]*schema.Schema{ - consts.FieldPath: { - Type: schema.TypeString, - Optional: true, - Description: "path to mount the backend", - Default: oktaAuthType, - ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { - value := v.(string) - if strings.HasSuffix(value, "/") { - errs = append(errs, errors.New("cannot write to a path ending in '/'")) - } - return - }, + fields := map[string]*schema.Schema{ + consts.FieldPath: { + Type: schema.TypeString, + Optional: true, + Description: "path to mount the backend", + Default: oktaAuthType, + ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { + value := v.(string) + if strings.HasSuffix(value, "/") { + errs = append(errs, errors.New("cannot write to a path ending in '/'")) + } + return }, + }, - "description": { - Type: schema.TypeString, - Required: false, - Optional: true, - Description: "The description of the auth backend", - }, + consts.FieldDescription: { + Type: schema.TypeString, + Required: false, + Optional: true, + Description: "The description of the auth backend", + }, - "organization": { - Type: schema.TypeString, - Required: true, - Optional: false, - Description: "The Okta organization. This will be the first part of the url https://XXX.okta.com.", - }, + consts.FieldOrganization: { + Type: schema.TypeString, + Required: true, + Optional: false, + Description: "The Okta organization. This will be the first part of the url https://XXX.okta.com.", + }, - "token": { - Type: schema.TypeString, - Required: false, - Optional: true, - Description: "The Okta API token. This is required to query Okta for user group membership. If this is not supplied only locally configured groups will be enabled.", - Sensitive: true, - }, + consts.FieldToken: { + Type: schema.TypeString, + Required: false, + Optional: true, + Description: "The Okta API token. This is required to query Okta for user group membership. If this is not supplied only locally configured groups will be enabled.", + Sensitive: true, + }, - "base_url": { - Type: schema.TypeString, - Required: false, - Optional: true, - Description: "The Okta url. Examples: oktapreview.com, okta.com (default)", - }, + consts.FieldBaseURL: { + Type: schema.TypeString, + Required: false, + Optional: true, + Description: "The Okta url. Examples: oktapreview.com, okta.com (default)", + }, - "bypass_okta_mfa": { - Type: schema.TypeBool, - Required: false, - Optional: true, - Description: "When true, requests by Okta for a MFA check will be bypassed. This also disallows certain status checks on the account, such as whether the password is expired.", - }, + fieldBypassOktaMFA: { + Type: schema.TypeBool, + Required: false, + Optional: true, + Description: "When true, requests by Okta for a MFA check will be bypassed. This also disallows certain status checks on the account, such as whether the password is expired.", + }, - "ttl": { - Type: schema.TypeString, - Required: false, - Optional: true, - Default: "0", - Description: "Duration after which authentication will be expired", - ValidateFunc: validateOktaTTL, - StateFunc: normalizeOktaTTL, - }, + consts.FieldTTL: { + Type: schema.TypeString, + Required: false, + Optional: true, + Default: "0", + Description: "Duration after which authentication will be expired", + ValidateFunc: validateOktaTTL, + StateFunc: normalizeOktaTTL, + Deprecated: "Deprecated. Please use `token_ttl` instead.", + }, - "max_ttl": { - Type: schema.TypeString, - Required: false, - Optional: true, - Description: "Maximum duration after which authentication will be expired", - Default: "0", - ValidateFunc: validateOktaTTL, - StateFunc: normalizeOktaTTL, - }, + consts.FieldMaxTTL: { + Type: schema.TypeString, + Required: false, + Optional: true, + Description: "Maximum duration after which authentication will be expired", + Default: "0", + ValidateFunc: validateOktaTTL, + StateFunc: normalizeOktaTTL, + Deprecated: "Deprecated. Please use `token_max_ttl` instead.", + }, - "group": { - Type: schema.TypeSet, - Required: false, - Optional: true, - Computed: true, - ConfigMode: schema.SchemaConfigModeAttr, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "group_name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the Okta group", + fieldGroup: { + Type: schema.TypeSet, + Required: false, + Optional: true, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + consts.FieldGroupName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the Okta group", + ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { + value := v.(string) + // No comma as it'll become part of a comma separate list + if strings.Contains(value, ",") { + errs = append(errs, errors.New("group cannot contain ','")) + } + return + }, + }, + + consts.FieldPolicies: { + Type: schema.TypeSet, + Required: true, + Description: "Policies to associate with this group", + Elem: &schema.Schema{ + Type: schema.TypeString, ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { value := v.(string) // No comma as it'll become part of a comma separate list if strings.Contains(value, ",") { - errs = append(errs, errors.New("group cannot contain ','")) + errs = append(errs, errors.New("policy cannot contain ','")) } return }, }, - - "policies": { - Type: schema.TypeSet, - Required: true, - Description: "Policies to associate with this group", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { - value := v.(string) - // No comma as it'll become part of a comma separate list - if strings.Contains(value, ",") { - errs = append(errs, errors.New("policy cannot contain ','")) - } - return - }, - }, - Set: schema.HashString, - }, + Set: schema.HashString, }, }, - Set: resourceOktaGroupHash, }, + Set: resourceOktaGroupHash, + }, - "user": { - Type: schema.TypeSet, - Required: false, - Optional: true, - Computed: true, - ConfigMode: schema.SchemaConfigModeAttr, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "groups": { - Type: schema.TypeSet, - Optional: true, - Description: "Groups within the Okta auth backend to associate with this user", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { - value := v.(string) - // No comma as it'll become part of a comma separate list - if strings.Contains(value, ",") { - errs = append(errs, errors.New("group cannot contain ','")) - } - return - }, - }, - Set: schema.HashString, - }, - - "username": { - Type: schema.TypeString, - Required: true, - Description: "Name of the user within Okta", + fieldUser: { + Type: schema.TypeSet, + Required: false, + Optional: true, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + fieldGroups: { + Type: schema.TypeSet, + Optional: true, + Description: "Groups within the Okta auth backend to associate with this user", + Elem: &schema.Schema{ + Type: schema.TypeString, ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { value := v.(string) - if strings.Contains(value, "/") { - errs = append(errs, errors.New("user cannot contain '/'")) + // No comma as it'll become part of a comma separate list + if strings.Contains(value, ",") { + errs = append(errs, errors.New("group cannot contain ','")) } return }, }, + Set: schema.HashString, + }, - "policies": { - Type: schema.TypeSet, - Required: false, - Optional: true, - Description: "Policies to associate with this user", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { - value := v.(string) - // No comma as it'll become part of a comma separate list - if strings.Contains(value, ",") { - errs = append(errs, errors.New("policy cannot contain ','")) - } - return - }, + consts.FieldUsername: { + Type: schema.TypeString, + Required: true, + Description: "Name of the user within Okta", + ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { + value := v.(string) + if strings.Contains(value, "/") { + errs = append(errs, errors.New("user cannot contain '/'")) + } + return + }, + }, + + consts.FieldPolicies: { + Type: schema.TypeSet, + Required: false, + Optional: true, + Description: "Policies to associate with this user", + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { + value := v.(string) + // No comma as it'll become part of a comma separate list + if strings.Contains(value, ",") { + errs = append(errs, errors.New("policy cannot contain ','")) + } + return }, - Set: schema.HashString, }, + Set: schema.HashString, }, }, - Set: resourceOktaUserHash, }, + Set: resourceOktaUserHash, + }, - "accessor": { - Type: schema.TypeString, - Computed: true, - Description: "The mount accessor related to the auth mount.", - }, + consts.FieldAccessor: { + Type: schema.TypeString, + Computed: true, + Description: "The mount accessor related to the auth mount.", + }, + } + + addTokenFields(fields, &addTokenFieldsConfig{}) + + return provider.MustAddMountMigrationSchema(&schema.Resource{ + CreateContext: oktaAuthBackendWrite, + DeleteContext: oktaAuthBackendDelete, + ReadContext: provider.ReadContextWrapper(oktaAuthBackendRead), + UpdateContext: oktaAuthBackendUpdate, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, }, + CustomizeDiff: getMountCustomizeDiffFunc(consts.FieldPath), + Schema: fields, }, false) } @@ -248,14 +262,14 @@ func parseDurationSeconds(i interface{}) (string, error) { return strconv.Itoa(int(d.Seconds())), nil } -func oktaAuthBackendWrite(d *schema.ResourceData, meta interface{}) error { +func oktaAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { - return e + diag.FromErr(e) } authType := oktaAuthType - desc := d.Get("description").(string) + desc := d.Get(consts.FieldDescription).(string) path := d.Get(consts.FieldPath).(string) log.Printf("[DEBUG] Writing auth %s to Vault", authType) @@ -265,42 +279,42 @@ func oktaAuthBackendWrite(d *schema.ResourceData, meta interface{}) error { Description: desc, }) if err != nil { - return fmt.Errorf("error writing to Vault: %s", err) + return diag.Errorf("error writing to Vault: %s", err) } log.Printf("[INFO] Enabled okta auth backend at '%s'", path) d.SetId(path) - return oktaAuthBackendUpdate(d, meta) + return oktaAuthBackendUpdate(ctx, d, meta) } -func oktaAuthBackendDelete(d *schema.ResourceData, meta interface{}) error { +func oktaAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { - return e + return diag.FromErr(e) } path := d.Id() log.Printf("[DEBUG] Deleting auth %s from Vault", path) - err := client.Sys().DisableAuth(path) + err := client.Sys().DisableAuthWithContext(ctx, path) if err != nil { - return fmt.Errorf("error disabling auth from Vault: %s", err) + return diag.Errorf("error disabling auth from Vault: %s", err) } return nil } -func oktaAuthBackendRead(d *schema.ResourceData, meta interface{}) error { +func oktaAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { - return e + return diag.FromErr(e) } path := d.Id() log.Printf("[DEBUG] Reading auth %s from Vault", path) - mount, err := mountutil.GetAuthMount(context.Background(), client, path) + mount, err := mountutil.GetAuthMount(ctx, client, path) if errors.Is(err, mountutil.ErrMountNotFound) { log.Printf("[WARN] Mount %q not found, removing from state.", path) d.SetId("") @@ -308,40 +322,40 @@ func oktaAuthBackendRead(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return err + return diag.FromErr(err) } if err := d.Set(consts.FieldPath, path); err != nil { - return err + return diag.FromErr(err) } - if err := d.Set("accessor", mount.Accessor); err != nil { - return err + if err := d.Set(consts.FieldAccessor, mount.Accessor); err != nil { + return diag.FromErr(err) } - if err := d.Set("description", mount.Description); err != nil { - return err + if err := d.Set(consts.FieldDescription, mount.Description); err != nil { + return diag.FromErr(err) } log.Printf("[DEBUG] Reading groups for mount %s from Vault", path) groups, err := oktaReadAllGroups(client, path) if err != nil { - return err + return diag.FromErr(err) } - if err := d.Set("group", groups); err != nil { - return err + if err := d.Set(fieldGroup, groups); err != nil { + return diag.FromErr(err) } log.Printf("[DEBUG] Reading users for mount %s from Vault", path) users, err := oktaReadAllUsers(client, path) if err != nil { - return err + return diag.FromErr(err) } - if err := d.Set("user", users); err != nil { - return err + if err := d.Set(fieldUser, users); err != nil { + return diag.FromErr(err) } if err := oktaReadAuthConfig(client, path, d); err != nil { - return err + return diag.FromErr(err) } return nil @@ -354,28 +368,14 @@ func oktaReadAuthConfig(client *api.Client, path string, d *schema.ResourceData) return err } - // map schema config TTL strings to okta auth TTL params. - // the provider input type of string does not match Vault's API of int64 - ttlFieldMap := map[string]string{ - "ttl": "token_ttl", - "max_ttl": "token_max_ttl", - } - for k, v := range ttlFieldMap { - if v, ok := config.Data[v]; ok { - s, err := parseutil.ParseString(v) - if err != nil { - return err - } - if err := d.Set(k, s); err != nil { - return err - } - } + if err := readTokenFields(d, config); err != nil { + return err } params := []string{ - "base_url", - "bypass_okta_mfa", - "organization", + consts.FieldBaseURL, + fieldBypassOktaMFA, + consts.FieldOrganization, } for _, param := range params { if err := d.Set(param, config.Data[param]); err != nil { @@ -386,10 +386,10 @@ func oktaReadAuthConfig(client *api.Client, path string, d *schema.ResourceData) return nil } -func oktaAuthBackendUpdate(d *schema.ResourceData, meta interface{}) error { +func oktaAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { - return e + return diag.FromErr(e) } path := d.Id() @@ -397,51 +397,45 @@ func oktaAuthBackendUpdate(d *schema.ResourceData, meta interface{}) error { if !d.IsNewResource() { path, e = util.Remount(d, client, consts.FieldPath, true) if e != nil { - return e + return diag.FromErr(e) } } log.Printf("[DEBUG] Updating auth %s in Vault", path) configuration := map[string]interface{}{ - "base_url": d.Get("base_url"), - "bypass_okta_mfa": d.Get("bypass_okta_mfa"), - "organization": d.Get("organization"), - "token": d.Get("token"), - } - - if ttl, ok := d.GetOk("ttl"); ok { - configuration["ttl"] = ttl + consts.FieldBaseURL: d.Get(consts.FieldBaseURL), + fieldBypassOktaMFA: d.Get(fieldBypassOktaMFA), + consts.FieldOrganization: d.Get(consts.FieldOrganization), + consts.FieldToken: d.Get(consts.FieldToken), } - if maxTtl, ok := d.GetOk("max_ttl"); ok { - configuration["max_ttl"] = maxTtl - } + updateTokenFields(d, configuration, false) - _, err := client.Logical().Write(oktaConfigEndpoint(path), configuration) + _, err := client.Logical().WriteWithContext(ctx, oktaConfigEndpoint(path), configuration) if err != nil { - return fmt.Errorf("error updating configuration to Vault for path %s: %s", path, err) + return diag.Errorf("error updating configuration to Vault for path %s: %s", path, err) } - if d.HasChange("group") { - oldValue, newValue := d.GetChange("group") + if d.HasChange(fieldGroup) { + oldValue, newValue := d.GetChange(fieldGroup) - err = oktaAuthUpdateGroups(d, client, path, oldValue, newValue) + err = oktaAuthUpdateGroups(client, path, oldValue, newValue) if err != nil { - return err + return diag.FromErr(err) } } - if d.HasChange("user") { - oldValue, newValue := d.GetChange("user") + if d.HasChange(fieldUser) { + oldValue, newValue := d.GetChange(fieldUser) - err = oktaAuthUpdateUsers(d, client, path, oldValue, newValue) + err = oktaAuthUpdateUsers(client, path, oldValue, newValue) if err != nil { - return err + return diag.FromErr(err) } } - return oktaAuthBackendRead(d, meta) + return oktaAuthBackendRead(ctx, d, meta) } func oktaReadAllGroups(client *api.Client, path string) (*schema.Set, error) { @@ -463,8 +457,8 @@ func oktaReadAllGroups(client *api.Client, path string) (*schema.Set, error) { } m := make(map[string]interface{}) - m["policies"] = policies - m["group_name"] = group.Name + m[consts.FieldPolicies] = policies + m[consts.FieldGroupName] = group.Name groups.Add(m) } @@ -496,9 +490,9 @@ func oktaReadAllUsers(client *api.Client, path string) (*schema.Set, error) { } m := make(map[string]interface{}) - m["policies"] = policies - m["groups"] = groups - m["username"] = user.Username + m[consts.FieldPolicies] = policies + m[fieldGroups] = groups + m[consts.FieldUsername] = user.Username users.Add(m) } @@ -506,12 +500,12 @@ func oktaReadAllUsers(client *api.Client, path string) (*schema.Set, error) { return users, nil } -func oktaAuthUpdateGroups(d *schema.ResourceData, client *api.Client, path string, oldValue, newValue interface{}) error { +func oktaAuthUpdateGroups(client *api.Client, path string, oldValue, newValue interface{}) error { groupsToDelete := oldValue.(*schema.Set).Difference(newValue.(*schema.Set)) newGroups := newValue.(*schema.Set).Difference(oldValue.(*schema.Set)) for _, group := range groupsToDelete.List() { - groupName := group.(map[string]interface{})["group_name"].(string) + groupName := group.(map[string]interface{})[consts.FieldGroupName].(string) log.Printf("[DEBUG] Removing Okta group %s from Vault", groupName) if err := deleteOktaGroup(client, path, groupName); err != nil { return fmt.Errorf("error removing group %s to Vault for path %s: %s", groupName, path, err) @@ -522,13 +516,13 @@ func oktaAuthUpdateGroups(d *schema.ResourceData, client *api.Client, path strin for _, v := range newGroups.List() { groupMapping := v.(map[string]interface{}) - groupName := groupMapping["group_name"].(string) + groupName := groupMapping[consts.FieldGroupName].(string) log.Printf("[DEBUG] Adding Okta group %s to Vault", groupName) group := oktaGroup{ Name: groupName, - Policies: util.ToStringArray(groupMapping["policies"].(*schema.Set).List()), + Policies: util.ToStringArray(groupMapping[consts.FieldPolicies].(*schema.Set).List()), } if err := updateOktaGroup(client, path, group); err != nil { @@ -541,12 +535,12 @@ func oktaAuthUpdateGroups(d *schema.ResourceData, client *api.Client, path strin return nil } -func oktaAuthUpdateUsers(d *schema.ResourceData, client *api.Client, path string, oldValue, newValue interface{}) error { +func oktaAuthUpdateUsers(client *api.Client, path string, oldValue, newValue interface{}) error { usersToDelete := oldValue.(*schema.Set).Difference(newValue.(*schema.Set)) newUsers := newValue.(*schema.Set).Difference(oldValue.(*schema.Set)) for _, user := range usersToDelete.List() { - userName := user.(map[string]interface{})["username"].(string) + userName := user.(map[string]interface{})[consts.FieldUsername].(string) log.Printf("[DEBUG] Removing Okta user %s from Vault", userName) if err := deleteOktaUser(client, path, userName); err != nil { return fmt.Errorf("error removing user %s mapping to Vault for path %s: %s", userName, path, err) @@ -557,14 +551,14 @@ func oktaAuthUpdateUsers(d *schema.ResourceData, client *api.Client, path string for _, v := range newUsers.List() { userMapping := v.(map[string]interface{}) - userName := userMapping["username"].(string) + userName := userMapping[consts.FieldUsername].(string) log.Printf("[DEBUG] Adding Okta user %s to Vault", userName) user := oktaUser{ Username: userName, - Policies: util.ToStringArray(userMapping["policies"].(*schema.Set).List()), - Groups: util.ToStringArray(userMapping["groups"].(*schema.Set).List()), + Policies: util.ToStringArray(userMapping[consts.FieldPolicies].(*schema.Set).List()), + Groups: util.ToStringArray(userMapping[fieldGroups].(*schema.Set).List()), } if err := updateOktaUser(client, path, user); err != nil { @@ -582,7 +576,7 @@ func resourceOktaGroupHash(v interface{}) int { if !castOk { return 0 } - if v, ok := m["group_name"]; ok { + if v, ok := m[consts.FieldGroupName]; ok { return helper.HashCodeString(v.(string)) } @@ -594,7 +588,7 @@ func resourceOktaUserHash(v interface{}) int { if !castOk { return 0 } - if v, ok := m["username"]; ok { + if v, ok := m[consts.FieldUsername]; ok { return helper.HashCodeString(v.(string)) } diff --git a/vault/resource_okta_auth_backend_group_test.go b/vault/resource_okta_auth_backend_group_test.go index 93de84742..e8a62a5e6 100644 --- a/vault/resource_okta_auth_backend_group_test.go +++ b/vault/resource_okta_auth_backend_group_test.go @@ -21,6 +21,7 @@ func TestAccOktaAuthBackendGroup_basic(t *testing.T) { t.Parallel() path := "okta-" + strconv.Itoa(acctest.RandInt()) organization := "dummy" + resourceName := "vault_okta_auth_backend_group.test" resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, @@ -31,7 +32,11 @@ func TestAccOktaAuthBackendGroup_basic(t *testing.T) { Config: testAccOktaAuthGroupConfig_basic(path, organization), Check: resource.ComposeTestCheckFunc( testAccOktaAuthBackendGroup_InitialCheck, - testAccOktaAuthBackend_GroupsCheck(path, "foo", []string{"one", "two", "default"}), + resource.TestCheckResourceAttr(resourceName, "group_name", "foo"), + resource.TestCheckResourceAttr(resourceName, "policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "policies.1", "one"), + resource.TestCheckResourceAttr(resourceName, "policies.2", "two"), ), }, { @@ -48,6 +53,7 @@ func TestAccOktaAuthBackendGroup_specialChar(t *testing.T) { t.Parallel() path := "okta-" + strconv.Itoa(acctest.RandInt()) organization := "dummy" + resourceName := "vault_okta_auth_backend_group.test" resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, @@ -58,7 +64,11 @@ func TestAccOktaAuthBackendGroup_specialChar(t *testing.T) { Config: testAccOktaAuthGroupConfig_specialChar(path, organization), Check: resource.ComposeTestCheckFunc( testAccOktaAuthBackendGroup_InitialCheck, - testAccOktaAuthBackend_GroupsCheck(path, "foo/bar", []string{"one", "two", "default"}), + resource.TestCheckResourceAttr(resourceName, "group_name", "foo/bar"), + resource.TestCheckResourceAttr(resourceName, "policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "policies.1", "one"), + resource.TestCheckResourceAttr(resourceName, "policies.2", "two"), ), }, { diff --git a/vault/resource_okta_auth_backend_test.go b/vault/resource_okta_auth_backend_test.go index a693bf38c..90e116812 100644 --- a/vault/resource_okta_auth_backend_test.go +++ b/vault/resource_okta_auth_backend_test.go @@ -4,44 +4,60 @@ package vault import ( - "encoding/json" "fmt" - "regexp" "testing" - "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/hashicorp/terraform-provider-vault/internal/provider" + "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/testutil" - "github.com/hashicorp/terraform-provider-vault/util" ) func TestAccOktaAuthBackend_basic(t *testing.T) { t.Parallel() organization := "example" path := resource.PrefixedUniqueId("okta-basic-") + resourceType := "vault_okta_auth_backend" + resourceName := resourceType + ".test" resource.Test(t, resource.TestCase{ PreCheck: func() { testutil.TestAccPreCheck(t) }, ProviderFactories: providerFactories, - CheckDestroy: testAccOktaAuthBackend_Destroyed(path), + CheckDestroy: testCheckMountDestroyed(resourceType, consts.MountTypeOkta, consts.FieldPath), Steps: []resource.TestStep{ { Config: testAccOktaAuthConfig_basic(path, organization), Check: resource.ComposeTestCheckFunc( - testAccOktaAuthBackend_InitialCheck, - testAccOktaAuthBackend_GroupsCheck(path, "dummy", []string{"one", "two", "default"}), - testAccOktaAuthBackend_UsersCheck(path, "foo", []string{"dummy"}, []string{}), + resource.TestCheckResourceAttr(resourceName, TokenFieldTTL, "3600"), + resource.TestCheckResourceAttr(resourceName, consts.FieldOrganization, "example"), + resource.TestCheckResourceAttr(resourceName, consts.FieldDescription, "Testing the Terraform okta auth backend"), + resource.TestCheckResourceAttrSet(resourceName, consts.FieldAccessor), + resource.TestCheckResourceAttr(resourceName, "group.#", "1"), + resource.TestCheckResourceAttr(resourceName, "group.0.group_name", "dummy"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.1", "one"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.2", "two"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.username", "foo"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.0", "dummy"), ), }, { Config: testAccOktaAuthConfig_updated(path, organization), Check: resource.ComposeTestCheckFunc( - testAccOktaAuthBackend_GroupsCheck(path, "example", []string{"three", "four", "default"}), - testAccOktaAuthBackend_UsersCheck(path, "bar", []string{"example"}, []string{}), + resource.TestCheckResourceAttr(resourceName, "group.#", "1"), + resource.TestCheckResourceAttr(resourceName, "group.0.group_name", "example"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.1", "four"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.2", "three"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.username", "bar"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.0", "example"), ), }, }, @@ -52,110 +68,132 @@ func TestAccOktaAuthBackend_import(t *testing.T) { t.Parallel() organization := "example" path := resource.PrefixedUniqueId("okta-import-") + resourceType := "vault_okta_auth_backend" + resourceName := resourceType + ".test" resource.Test(t, resource.TestCase{ PreCheck: func() { testutil.TestAccPreCheck(t) }, ProviderFactories: providerFactories, - CheckDestroy: testAccOktaAuthBackend_Destroyed(path), + CheckDestroy: testCheckMountDestroyed(resourceType, consts.MountTypeOkta, consts.FieldPath), Steps: []resource.TestStep{ { Config: testAccOktaAuthConfig_basic(path, organization), Check: resource.ComposeTestCheckFunc( - testAccOktaAuthBackend_InitialCheck, - testAccOktaAuthBackend_GroupsCheck(path, "dummy", []string{"one", "two", "default"}), - testAccOktaAuthBackend_UsersCheck(path, "foo", []string{"dummy"}, []string{}), + resource.TestCheckResourceAttr(resourceName, TokenFieldTTL, "3600"), + resource.TestCheckResourceAttr(resourceName, consts.FieldOrganization, "example"), + resource.TestCheckResourceAttr(resourceName, consts.FieldDescription, "Testing the Terraform okta auth backend"), + resource.TestCheckResourceAttrSet(resourceName, consts.FieldAccessor), + resource.TestCheckResourceAttr(resourceName, "group.#", "1"), + resource.TestCheckResourceAttr(resourceName, "group.0.group_name", "dummy"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.1", "one"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.2", "two"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.username", "foo"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.0", "dummy"), ), }, - { - ResourceName: "vault_okta_auth_backend.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "token", - "disable_remount", - }, - }, + testutil.GetImportTestStep(resourceName, false, nil, + "token", + "disable_remount", + "ttl", + "max_ttl"), { Config: testAccOktaAuthConfig_updated(path, organization), Check: resource.ComposeTestCheckFunc( - testAccOktaAuthBackend_GroupsCheck(path, "example", []string{"three", "four", "default"}), - testAccOktaAuthBackend_UsersCheck(path, "bar", []string{"example"}, []string{}), + resource.TestCheckResourceAttr(resourceName, "group.#", "1"), + resource.TestCheckResourceAttr(resourceName, "group.0.group_name", "example"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.#", "3"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.1", "four"), + resource.TestCheckResourceAttr(resourceName, "group.0.policies.2", "three"), + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.username", "bar"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.groups.0", "example"), ), }, - { - ResourceName: "vault_okta_auth_backend.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "token", - "disable_remount", - }, - }, + testutil.GetImportTestStep(resourceName, false, nil, + "token", + "disable_remount", + "ttl", + "max_ttl"), }, }) } -func TestAccOktaAuthBackend_invalid_ttl(t *testing.T) { +func TestAccOktaAuthBackend_groups_optional(t *testing.T) { t.Parallel() organization := "example" - path := resource.PrefixedUniqueId("okta-invalid-ttl-") + path := resource.PrefixedUniqueId("okta-group-optional") + resourceType := "vault_okta_auth_backend" + resourceName := resourceType + ".test" resource.Test(t, resource.TestCase{ PreCheck: func() { testutil.TestAccPreCheck(t) }, ProviderFactories: providerFactories, - CheckDestroy: testAccOktaAuthBackend_Destroyed(path), + CheckDestroy: testCheckMountDestroyed(resourceType, consts.MountTypeOkta, consts.FieldPath), Steps: []resource.TestStep{ { - Config: testAccOktaAuthConfig_invalid_ttl(path, organization), - ExpectError: regexp.MustCompile(`Error: invalid value for "ttl", could not parse "invalid_ttl"`), + Config: testAccOktaAuthConfig_groups_optional(path, organization), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "user.#", "1"), + resource.TestCheckResourceAttr(resourceName, "user.0.username", "bar"), + resource.TestCheckResourceAttr(resourceName, "user.0.policies.#", "2"), + resource.TestCheckResourceAttr(resourceName, "user.0.policies.0", "default"), + resource.TestCheckResourceAttr(resourceName, "user.0.policies.1", "eng"), + ), }, }, }) } -func TestAccOktaAuthBackend_invalid_max_ttl(t *testing.T) { +func TestAccOktaAuthBackend_remount(t *testing.T) { t.Parallel() + path := acctest.RandomWithPrefix("tf-test-auth-okta") + updatedPath := acctest.RandomWithPrefix("tf-test-auth-okta-updated") + organization := "example" - path := resource.PrefixedUniqueId("okta-invalid_max_ttl-") + resourceName := "vault_okta_auth_backend.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testutil.TestAccPreCheck(t) }, ProviderFactories: providerFactories, - CheckDestroy: testAccOktaAuthBackend_Destroyed(path), + PreCheck: func() { testutil.TestAccPreCheck(t) }, Steps: []resource.TestStep{ { - Config: testAccOktaAuthConfig_invalid_max_ttl(path, organization), - ExpectError: regexp.MustCompile(`Error: invalid value for "max_ttl", could not parse "invalid_max_ttl"`), + Config: testAccOktaAuthConfig_basic(path, organization), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, consts.FieldPath, path), + resource.TestCheckResourceAttr(resourceName, TokenFieldTTL, "3600"), + resource.TestCheckResourceAttr(resourceName, consts.FieldOrganization, "example"), + resource.TestCheckResourceAttr(resourceName, consts.FieldDescription, "Testing the Terraform okta auth backend"), + resource.TestCheckResourceAttrSet(resourceName, consts.FieldAccessor), + ), }, - }, - }) -} - -func TestAccOktaAuthBackend_groups_optional(t *testing.T) { - t.Parallel() - organization := "example" - path := resource.PrefixedUniqueId("okta-group-optional") - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testutil.TestAccPreCheck(t) }, - ProviderFactories: providerFactories, - CheckDestroy: testAccOktaAuthBackend_Destroyed(path), - Steps: []resource.TestStep{ { - Config: testAccOktaAuthConfig_groups_optional(path, organization), + Config: testAccOktaAuthConfig_basic(updatedPath, organization), Check: resource.ComposeTestCheckFunc( - testAccOktaAuthBackend_UsersCheck(path, "bar", []string{}, []string{"eng", "default"}), + resource.TestCheckResourceAttr(resourceName, consts.FieldPath, updatedPath), + resource.TestCheckResourceAttr(resourceName, TokenFieldTTL, "3600"), + resource.TestCheckResourceAttr(resourceName, consts.FieldOrganization, "example"), + resource.TestCheckResourceAttr(resourceName, consts.FieldDescription, "Testing the Terraform okta auth backend"), + resource.TestCheckResourceAttrSet(resourceName, consts.FieldAccessor), ), }, + testutil.GetImportTestStep(resourceName, false, nil, + "token", + "disable_remount", + "ttl", + "max_ttl"), }, }) } -func TestAccOktaAuthBackend_remount(t *testing.T) { +func TestAccOktaAuthBackend_TokenFields(t *testing.T) { t.Parallel() path := acctest.RandomWithPrefix("tf-test-auth-okta") - updatedPath := acctest.RandomWithPrefix("tf-test-auth-okta-updated") - organization := "example" resourceName := "vault_okta_auth_backend.test" @@ -164,20 +202,22 @@ func TestAccOktaAuthBackend_remount(t *testing.T) { PreCheck: func() { testutil.TestAccPreCheck(t) }, Steps: []resource.TestStep{ { - Config: testAccOktaAuthConfig_basic(path, organization), + Config: testAccOktaAuthConfig_tokenFields(path, organization), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "path", path), - testAccOktaAuthBackend_InitialCheck, + resource.TestCheckResourceAttr(resourceName, consts.FieldPath, path), + resource.TestCheckResourceAttr(resourceName, "token_policies.#", "2"), + resource.TestCheckResourceAttr(resourceName, "token_policies.0", "policy_a"), + resource.TestCheckResourceAttr(resourceName, "token_policies.1", "policy_b"), + resource.TestCheckResourceAttr(resourceName, TokenFieldTTL, "300"), + resource.TestCheckResourceAttr(resourceName, TokenFieldMaxTTL, "600"), + resource.TestCheckResourceAttr(resourceName, TokenFieldNoDefaultPolicy, "false"), ), }, - { - Config: testAccOktaAuthConfig_basic(updatedPath, organization), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "path", updatedPath), - testAccOktaAuthBackend_InitialCheck, - ), - }, - testutil.GetImportTestStep(resourceName, false, nil, "token", "disable_remount"), + testutil.GetImportTestStep(resourceName, false, nil, + "token", + "disable_remount", + "ttl", + "max_ttl"), }, }) } @@ -189,7 +229,7 @@ resource "vault_okta_auth_backend" "test" { path = "%s" organization = "%s" token = "this must be kept secret" - ttl = "1h" + token_ttl = 3600 group { group_name = "dummy" policies = ["one", "two", "default"] @@ -221,32 +261,6 @@ resource "vault_okta_auth_backend" "test" { `, path, organization) } -func testAccOktaAuthConfig_invalid_ttl(path string, organization string) string { - return fmt.Sprintf(` -resource "vault_okta_auth_backend" "test" { - description = "Testing the Terraform okta auth backend" - path = "%s" - organization = "%s" - token = "this must be kept secret" - ttl = "invalid_ttl" - max_ttl = "1h" -} -`, path, organization) -} - -func testAccOktaAuthConfig_invalid_max_ttl(path string, organization string) string { - return fmt.Sprintf(` -resource "vault_okta_auth_backend" "test" { - description = "Testing the Terraform okta auth backend" - path = "%s" - organization = "%s" - token = "this must be kept secret" - ttl = "1h" - max_ttl = "invalid_max_ttl" -} -`, path, organization) -} - func testAccOktaAuthConfig_groups_optional(path string, organization string) string { return fmt.Sprintf(` resource "vault_okta_auth_backend" "test" { @@ -262,188 +276,14 @@ resource "vault_okta_auth_backend" "test" { `, path, organization) } -func testAccOktaAuthBackend_InitialCheck(s *terraform.State) error { - resourceState := s.Modules[0].Resources["vault_okta_auth_backend.test"] - if resourceState == nil { - return fmt.Errorf("resource not found in state") - } - - instanceState := resourceState.Primary - if instanceState == nil { - return fmt.Errorf("resource has no primary instance") - } - - path := instanceState.ID - - if path != instanceState.Attributes["path"] { - return fmt.Errorf("id doesn't match path") - } - - client, e := provider.GetClient(instanceState, testProvider.Meta()) - if e != nil { - return e - } - - authMounts, err := client.Sys().ListAuth() - if err != nil { - return err - } - - authMount := authMounts[path+"/"] - - if authMount == nil { - return fmt.Errorf("auth mount %s not present", path) - } - - if "okta" != authMount.Type { - return fmt.Errorf("incorrect mount type: %s", authMount.Type) - } - - if "Testing the Terraform okta auth backend" != authMount.Description { - return fmt.Errorf("incorrect description: %s", authMount.Description) - } - - config, err := client.Logical().Read(fmt.Sprintf("/auth/%s/config", path)) - if err != nil { - return fmt.Errorf("error reading back configuration: %s", err) - } - - if "example" != config.Data["organization"] { - return fmt.Errorf("incorrect organization: %s", config.Data["organization"]) - } - - ttl, err := config.Data["ttl"].(json.Number).Int64() - if err != nil { - return err - } - - if int64((time.Hour * 1).Seconds()) != ttl { - return fmt.Errorf("incorrect ttl: %s", config.Data["ttl"]) - } - - if instanceState.Attributes["accessor"] != authMount.Accessor { - return fmt.Errorf("incorrect accessor: %s", instanceState.Attributes["accessor"]) - } - - return nil -} - -func testAccOktaAuthBackend_GroupsCheck(path, groupName string, expectedPolicies []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - client := testProvider.Meta().(*provider.ProviderMeta).MustGetClient() - - groupList, err := client.Logical().List(fmt.Sprintf("/auth/%s/groups", path)) - if err != nil { - return fmt.Errorf("error reading back group configuration: %s", err) - } - - if len(groupList.Data["keys"].([]interface{})) != 1 { - return fmt.Errorf("unexpected groups present: %v", groupList.Data) - } - - dummyGroup, err := client.Logical().Read(fmt.Sprintf("/auth/%s/groups/%s", path, groupName)) - if err != nil { - return fmt.Errorf("error reading back configuration: %s", err) - } - - var missing []interface{} - - actual := util.ToStringArray(dummyGroup.Data["policies"].([]interface{})) - EXPECTED: - for _, i := range expectedPolicies { - for _, j := range actual { - if i == j { - continue EXPECTED - } - } - - missing = append(missing, i) - } - - if len(missing) != 0 { - return fmt.Errorf("group policies incorrect; expected %[1]v, actual %[2]v (types: %[1]T, %[2]T)", expectedPolicies, actual) - } - - return nil - } -} - -func testAccOktaAuthBackend_UsersCheck(path, userName string, expectedGroups, expectedPolicies []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - client := testProvider.Meta().(*provider.ProviderMeta).MustGetClient() - - userList, err := client.Logical().List(fmt.Sprintf("/auth/%s/users", path)) - if err != nil { - return fmt.Errorf("error reading back configuration: %s", err) - } - - if len(userList.Data["keys"].([]interface{})) != 1 { - return fmt.Errorf("unexpected users present: %v", userList.Data) - } - - user, err := client.Logical().Read(fmt.Sprintf("/auth/%s/users/%s", path, userName)) - if err != nil { - return fmt.Errorf("error reading back configuration: %s", err) - } - - var missing []interface{} - - actual := util.ToStringArray(user.Data["policies"].([]interface{})) - if len(expectedPolicies) != len(actual) { - return fmt.Errorf("expected %d policies, got %d", len(expectedPolicies), len(actual)) - } - EXPECTED_POLICIES: - for _, i := range expectedPolicies { - for _, j := range actual { - if i == j { - continue EXPECTED_POLICIES - } - } - - missing = append(missing, i) - } - - if len(missing) != 0 { - return fmt.Errorf("user policies incorrect; expected %[1]v (len: %[3]d), actual %[2]v (len: %[4]d) (types: %[1]T, %[2]T)", expectedPolicies, actual, len(expectedPolicies), len(actual)) - } - - actual = util.ToStringArray(user.Data["groups"].([]interface{})) - - if len(expectedGroups) != len(actual) { - return fmt.Errorf("expected %d groups, got %d", len(expectedGroups), len(actual)) - } - EXPECTED_GROUPS: - for _, i := range expectedGroups { - for _, j := range actual { - if i == j { - continue EXPECTED_GROUPS - } - } - - missing = append(missing, i) - } - - if len(missing) != 0 { - return fmt.Errorf("user groups incorrect; expected %[1]v, actual %[2]v (types: %[1]T, %[2]T)", expectedGroups, actual) - } - - return nil - } +func testAccOktaAuthConfig_tokenFields(path string, organization string) string { + return fmt.Sprintf(` +resource "vault_okta_auth_backend" "test" { + path = "%s" + organization = "%s" + token_ttl = 300 + token_max_ttl = 600 + token_policies = ["policy_a", "policy_b"] } - -func testAccOktaAuthBackend_Destroyed(path string) resource.TestCheckFunc { - return func(s *terraform.State) error { - client := testProvider.Meta().(*provider.ProviderMeta).MustGetClient() - - authMounts, err := client.Sys().ListAuth() - if err != nil { - return err - } - - if _, ok := authMounts[fmt.Sprintf("%s/", path)]; ok { - return fmt.Errorf("auth mount not destroyed") - } - - return nil - } +`, path, organization) } diff --git a/vault/resource_okta_auth_backend_user_test.go b/vault/resource_okta_auth_backend_user_test.go index faebbadc8..6d2e10ec8 100644 --- a/vault/resource_okta_auth_backend_user_test.go +++ b/vault/resource_okta_auth_backend_user_test.go @@ -21,6 +21,7 @@ func TestAccOktaAuthBackendUser(t *testing.T) { t.Parallel() path := "okta-" + strconv.Itoa(acctest.RandInt()) organization := "dummy" + resourceName := "vault_okta_auth_backend_user.test" resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, @@ -31,7 +32,12 @@ func TestAccOktaAuthBackendUser(t *testing.T) { Config: testAccOktaAuthUserConfig(path, organization), Check: resource.ComposeTestCheckFunc( testAccOktaAuthBackendUser_InitialCheck, - testAccOktaAuthBackend_UsersCheck(path, "user_test", []string{"one", "two"}, []string{"three"}), + resource.TestCheckResourceAttr(resourceName, "username", "user_test"), + resource.TestCheckResourceAttr(resourceName, "groups.#", "2"), + resource.TestCheckResourceAttr(resourceName, "groups.0", "one"), + resource.TestCheckResourceAttr(resourceName, "groups.1", "two"), + resource.TestCheckResourceAttr(resourceName, "policies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "policies.0", "three"), ), }, }, diff --git a/website/docs/r/okta_auth_backend.html.md b/website/docs/r/okta_auth_backend.html.md index 8f32093da..fee0805fb 100644 --- a/website/docs/r/okta_auth_backend.html.md +++ b/website/docs/r/okta_auth_backend.html.md @@ -82,6 +82,45 @@ If this is not supplied only locally configured groups will be enabled. * `policies` - (Optional) List of Vault policies to associate with this user +### Common Token Arguments + +These arguments are common across several Authentication Token resources since Vault 1.2. + +* `token_ttl` - (Optional) The incremental lifetime for generated tokens in number of seconds. + Its current value will be referenced at renewal time. + +* `token_max_ttl` - (Optional) The maximum lifetime for generated tokens in number of seconds. + Its current value will be referenced at renewal time. + +* `token_period` - (Optional) If set, indicates that the + token generated using this role should never expire. The token should be renewed within the + duration specified by this value. At each renewal, the token's TTL will be set to the + value of this field. Specified in seconds. + +* `token_policies` - (Optional) List of policies to encode onto generated tokens. Depending + on the auth method, this list may be supplemented by user/group/other values. + +* `token_bound_cidrs` - (Optional) List of CIDR blocks; if set, specifies blocks of IP + addresses which can authenticate successfully, and ties the resulting token to these blocks + as well. + +* `token_explicit_max_ttl` - (Optional) If set, will encode an + [explicit max TTL](https://www.vaultproject.io/docs/concepts/tokens.html#token-time-to-live-periodic-tokens-and-explicit-max-ttls) + onto the token in number of seconds. This is a hard cap even if `token_ttl` and + `token_max_ttl` would otherwise allow a renewal. + +* `token_no_default_policy` - (Optional) If set, the default policy will not be set on + generated tokens; otherwise it will be added to the policies set in token_policies. + +* `token_num_uses` - (Optional) The [maximum number](https://www.vaultproject.io/api-docs/gcp#token_num_uses) + of times a generated token may be used (within its lifetime); 0 means unlimited. + +* `token_type` - (Optional) The type of token that should be generated. Can be `service`, + `batch`, or `default` to use the mount's tuned default (which unless changed will be + `service` tokens). For token store roles, there are two additional possibilities: + `default-service` and `default-batch` which specify the type to return unless the client + requests a different type at generation time. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: