Skip to content

Commit

Permalink
Swallow 403 errors when user resource attempts to inspect admin roles
Browse files Browse the repository at this point in the history
while using a non-super admin API token.

Closes #1216
  • Loading branch information
monde committed Nov 16, 2022
1 parent ceee6a9 commit 1e3bf94
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 12 deletions.
2 changes: 1 addition & 1 deletion okta/data_source_okta_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func dataSourceUsersRead(ctx context.Context, d *schema.ResourceData, m interfac
rawMap["group_memberships"] = groups
}
if includeRoles {
roles, err := getAdminRoles(ctx, user.Id, client)
roles, _, err := getAdminRoles(ctx, user.Id, client)
if err != nil {
return diag.Errorf("failed to set user's admin roles: %v", err)
}
Expand Down
41 changes: 41 additions & 0 deletions okta/resource_okta_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,44 @@ resource okta_user "test" {
}
`, r)
}

// TestIssue1216Suppress403Errors
// https://github.com/okta/terraform-provider-okta/issues/1216 When this test
// runs with an API token of Org Admin (not Super Admin) the resource will fail
// when the admin roles are gathered.
func TestIssue1216Suppress403Errors(t *testing.T) {
if !orgAdminOnlyTest(t) {
return
}
ri := acctest.RandInt()
mgr := newFixtureManager(user)
config := `
resource "okta_user" "test" {
first_name = "TestAcc"
last_name = "Smith"
login = "testAcc-replace_with_uuid@example.com"
email = "testAcc-replace_with_uuid@example.com"
}`
config = mgr.ConfigReplace(config, ri)
resourceName := fmt.Sprintf("%s.test", user)
email := fmt.Sprintf("testAcc-%d@example.com", ri)

resource.Test(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
CheckDestroy: testAccCheckUserDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "first_name", "TestAcc"),
resource.TestCheckResourceAttr(resourceName, "last_name", "Smith"),
resource.TestCheckResourceAttr(resourceName, "login", email),
resource.TestCheckResourceAttr(resourceName, "email", email),
resource.TestCheckResourceAttr(resourceName, "admin_roles.#", "0"),
),
},
},
})
}
16 changes: 5 additions & 11 deletions okta/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"log"
"net/http"
"reflect"
"time"

Expand Down Expand Up @@ -274,29 +273,24 @@ func listUserOnlyRoles(ctx context.Context, c *okta.Client, userID string) (user
return
}

func getAdminRoles(ctx context.Context, id string, c *okta.Client) ([]interface{}, error) {
func getAdminRoles(ctx context.Context, id string, c *okta.Client) ([]interface{}, *okta.Response, error) {
roleTypes := make([]interface{}, 0)

roles, resp, err := listUserOnlyRoles(ctx, c, id)

if err != nil {
if resp != nil && resp.StatusCode == http.StatusForbidden {
// no-op
} else {
return nil, err
}
return roleTypes, resp, err
} else {
for _, role := range roles {
roleTypes = append(roleTypes, role.Type)
}
}

return roleTypes, err
return roleTypes, resp, err
}

func setAdminRoles(ctx context.Context, d *schema.ResourceData, m interface{}) error {
roleTypes, err := getAdminRoles(ctx, d.Id(), getOktaClientFromMetadata(m))
if err != nil {
roleTypes, resp, err := getAdminRoles(ctx, d.Id(), getOktaClientFromMetadata(m))
if err := suppressErrorOn403("setting admin roles", m, resp, err); err != nil {
return fmt.Errorf("failed to get admin roles: %v", err)
}

Expand Down
10 changes: 10 additions & 0 deletions okta/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,16 @@ func suppressErrorOn401(what string, meta interface{}, resp *okta.Response, err
return responseErr(resp, err)
}

// Useful shortcut for suppressing errors from Okta's SDK when a Org does not
// have permission to access a feature.
func suppressErrorOn403(what string, meta interface{}, resp *okta.Response, err error) error {
if resp != nil && resp.StatusCode == http.StatusForbidden {
logger(meta).Warn(fmt.Sprintf("Suppressing %q on %q", "403 Forbidden", what))
return nil
}
return responseErr(resp, err)
}

func getParallelismFromMetadata(meta interface{}) int {
return meta.(*Config).parallelism
}
Expand Down
5 changes: 5 additions & 0 deletions website/docs/r/user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Creates an Okta User.

This resource allows you to create and configure an Okta User.

~> **IMPORTANT** If the provider is executed with a non-super user API token a
403 occurs when the provider attempts to inspect the user's admin roles. This
403 is swallowed and a warning is logged allowing the resource to continue
without this error hindering it.

## Example Usage

Full profile:
Expand Down

0 comments on commit 1e3bf94

Please sign in to comment.