-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DXCDT-428: User permissions resource (#578)
* Initial commit for user permissions relationship resource * Updating example * Integrating into provider * Re-recording test * Custom doc templates for user permission and user permissions * Adding update function, re-recording tests * Stronger tests --------- Co-authored-by: Will Vedder <will.vedder@okta.com>
- Loading branch information
Showing
11 changed files
with
3,726 additions
and
467 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
--- | ||
page_title: "Resource: auth0_user_permissions" | ||
description: |- | ||
With this resource, you can manage all of a user's permissions. | ||
--- | ||
|
||
# Resource: auth0_user_permissions | ||
|
||
With this resource, you can manage all of a user's permissions. | ||
|
||
!> To prevent issues, avoid using this resource together with the `auth0_user_permission` resource. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "auth0_resource_server" "resource_server" { | ||
name = "Example Resource Server (Managed by Terraform)" | ||
identifier = "https://api.example.com" | ||
scopes { | ||
value = "create:foo" | ||
description = "Create foos" | ||
} | ||
scopes { | ||
value = "read:foo" | ||
description = "Read foos" | ||
} | ||
} | ||
resource "auth0_user" "user" { | ||
connection_name = "Username-Password-Authentication" | ||
user_id = "12345" | ||
username = "unique_username" | ||
name = "Firstname Lastname" | ||
nickname = "some.nickname" | ||
email = "test@test.com" | ||
email_verified = true | ||
password = "passpass$12$12" | ||
picture = "https://www.example.com/a-valid-picture-url.jpg" | ||
} | ||
resource "auth0_user_permissions" "all_user_permissions" { | ||
user_id = auth0_user.user.id | ||
permissions { | ||
name = tolist(auth0_resource_server.resource_server.scopes)[0] | ||
resource_server_identifier = auth0_resource_server.resource_server.identifier | ||
} | ||
permissions { | ||
name = tolist(auth0_resource_server.resource_server.scopes)[1] | ||
resource_server_identifier = auth0_resource_server.resource_server.identifier | ||
} | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `permissions` (Block Set, Min: 1) List of API permissions granted to the user. (see [below for nested schema](#nestedblock--permissions)) | ||
- `user_id` (String) ID of the user to associate the permission to. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. | ||
|
||
<a id="nestedblock--permissions"></a> | ||
### Nested Schema for `permissions` | ||
|
||
Required: | ||
|
||
- `name` (String) Name of permission. | ||
- `resource_server_identifier` (String) Resource server identifier associated with the permission. | ||
|
||
Read-Only: | ||
|
||
- `description` (String) Description of the permission. | ||
- `resource_server_name` (String) Name of resource server that the permission is associated with. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
# This resource can be imported by specifying the user ID | ||
|
||
# Example: | ||
terraform import auth0_user_permissions.all_user_permissions "auth0|111111111111111111111111" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# This resource can be imported by specifying the user ID | ||
|
||
# Example: | ||
terraform import auth0_user_permissions.all_user_permissions "auth0|111111111111111111111111" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
resource "auth0_resource_server" "resource_server" { | ||
name = "Example Resource Server (Managed by Terraform)" | ||
identifier = "https://api.example.com" | ||
scopes { | ||
value = "create:foo" | ||
description = "Create foos" | ||
} | ||
|
||
scopes { | ||
value = "read:foo" | ||
description = "Read foos" | ||
} | ||
} | ||
|
||
resource "auth0_user" "user" { | ||
connection_name = "Username-Password-Authentication" | ||
user_id = "12345" | ||
username = "unique_username" | ||
name = "Firstname Lastname" | ||
nickname = "some.nickname" | ||
email = "test@test.com" | ||
email_verified = true | ||
password = "passpass$12$12" | ||
picture = "https://www.example.com/a-valid-picture-url.jpg" | ||
} | ||
|
||
resource "auth0_user_permissions" "all_user_permissions" { | ||
user_id = auth0_user.user.id | ||
|
||
permissions { | ||
name = tolist(auth0_resource_server.resource_server.scopes)[0] | ||
resource_server_identifier = auth0_resource_server.resource_server.identifier | ||
} | ||
|
||
permissions { | ||
name = tolist(auth0_resource_server.resource_server.scopes)[1] | ||
resource_server_identifier = auth0_resource_server.resource_server.identifier | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package user | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
"github.com/auth0/go-auth0" | ||
"github.com/auth0/go-auth0/management" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
|
||
"github.com/auth0/terraform-provider-auth0/internal/config" | ||
"github.com/auth0/terraform-provider-auth0/internal/value" | ||
) | ||
|
||
// NewPermissionsResource will return a new auth0_connection_client resource. | ||
func NewPermissionsResource() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"user_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "ID of the user to associate the permission to.", | ||
}, | ||
"permissions": { | ||
Type: schema.TypeSet, | ||
Required: true, | ||
Description: "List of API permissions granted to the user.", | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Name of permission.", | ||
}, | ||
"resource_server_identifier": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Resource server identifier associated with the permission.", | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Description of the permission.", | ||
}, | ||
"resource_server_name": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Name of resource server that the permission is associated with.", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
CreateContext: upsertUserPermissions, | ||
UpdateContext: upsertUserPermissions, | ||
ReadContext: readUserPermissions, | ||
DeleteContext: deleteUserPermissions, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
Description: "With this resource, you can manage all of a user's permissions.", | ||
} | ||
} | ||
|
||
func upsertUserPermissions(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
api := meta.(*config.Config).GetAPI() | ||
mutex := meta.(*config.Config).GetMutex() | ||
|
||
userID := data.Get("user_id").(string) | ||
|
||
if !data.HasChange("permissions") { | ||
return nil | ||
} | ||
|
||
mutex.Lock(userID) | ||
defer mutex.Unlock(userID) | ||
|
||
toAdd, toRemove := value.Difference(data, "permissions") | ||
|
||
var addPermissions []*management.Permission | ||
for _, addPermission := range toAdd { | ||
permission := addPermission.(map[string]interface{}) | ||
addPermissions = append(addPermissions, &management.Permission{ | ||
Name: auth0.String(permission["name"].(string)), | ||
ResourceServerIdentifier: auth0.String(permission["resource_server_identifier"].(string)), | ||
}) | ||
} | ||
|
||
if len(addPermissions) > 0 { | ||
if err := api.User.AssignPermissions(userID, addPermissions); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
} | ||
|
||
var rmPermissions []*management.Permission | ||
for _, rmPermission := range toRemove { | ||
permission := rmPermission.(map[string]interface{}) | ||
rmPermissions = append(rmPermissions, &management.Permission{ | ||
Name: auth0.String(permission["name"].(string)), | ||
ResourceServerIdentifier: auth0.String(permission["resource_server_identifier"].(string)), | ||
}) | ||
} | ||
|
||
if len(rmPermissions) > 0 { | ||
if err := api.User.RemovePermissions(userID, rmPermissions); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
} | ||
|
||
data.SetId(userID) | ||
|
||
return readUserPermissions(ctx, data, meta) | ||
} | ||
|
||
func readUserPermissions(_ context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
api := meta.(*config.Config).GetAPI() | ||
|
||
userID := data.Get("user_id").(string) | ||
|
||
permissions, err := api.User.Permissions(userID) | ||
if err != nil { | ||
if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound { | ||
data.SetId("") | ||
return nil | ||
} | ||
return diag.FromErr(err) | ||
} | ||
|
||
err = data.Set("permissions", flattenUserPermissions(permissions)) | ||
|
||
return diag.FromErr(err) | ||
} | ||
|
||
func deleteUserPermissions(_ context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
api := meta.(*config.Config).GetAPI() | ||
mutex := meta.(*config.Config).GetMutex() | ||
|
||
userID := data.Get("user_id").(string) | ||
|
||
mutex.Lock(userID) | ||
defer mutex.Unlock(userID) | ||
|
||
permissions, err := api.User.Permissions(userID) | ||
if err != nil { | ||
if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound { | ||
data.SetId("") | ||
return nil | ||
} | ||
return diag.FromErr(err) | ||
} | ||
|
||
var rmPermissions []*management.Permission | ||
for _, rmPermission := range permissions.Permissions { | ||
rmPermissions = append(rmPermissions, &management.Permission{ | ||
Name: auth0.String(rmPermission.GetName()), | ||
ResourceServerIdentifier: auth0.String(rmPermission.GetResourceServerIdentifier()), | ||
}) | ||
} | ||
if err := api.User.RemovePermissions( | ||
userID, | ||
rmPermissions, | ||
); err != nil { | ||
if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound { | ||
data.SetId("") | ||
return nil | ||
} | ||
return diag.FromErr(err) | ||
} | ||
|
||
data.SetId("") | ||
return nil | ||
} |
Oops, something went wrong.