Skip to content

Commit 3999572

Browse files
committed
Enhance okta_app_user_assignments data source to return detailed user information
- Adds support for returning full user profile and credentials in the data source - Improves time formatting, pagination, and test coverage - Updates documentation and example usage Closes #1844
1 parent 9000a9f commit 3999572

4 files changed

Lines changed: 239 additions & 12 deletions

File tree

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,62 @@
11
---
22
page_title: "Data Source: okta_app_user_assignments"
33
description: |-
4-
Get a set of users assigned to an Okta application.
4+
Get a set of users assigned to an Okta application with detailed information.
55
---
66

77
# Data Source: okta_app_user_assignments
88

9-
Get a set of users assigned to an Okta application.
9+
Get a set of users assigned to an Okta application with detailed information including user status, scope, profile data, and credentials.
1010

1111
## Example Usage
1212

1313
```terraform
1414
data "okta_app_user_assignments" "test" {
1515
id = okta_app_oauth.test.id
1616
}
17+
18+
# Access user details
19+
output "user_details" {
20+
value = data.okta_app_user_assignments.test.users
21+
}
1722
```
1823

1924
<!-- schema generated by tfplugindocs -->
25+
2026
## Schema
2127

2228
### Required
2329

24-
- `id` (String) ID of the Okta App being queried for groups
30+
- `id` (String) ID of the Okta App being queried for users
2531

2632
### Read-Only
2733

28-
- `users` (Set of String) List of user IDs assigned to the app
34+
- `users` (Set of Object) List of users assigned to the app with detailed information (see [below for nested schema](#nestedblock--users))
35+
36+
<a id="nestedblock--users"></a>
37+
38+
### Nested Schema for `users`
39+
40+
Read-Only:
41+
42+
- `created` (String) Timestamp when the Application User was created
43+
- `credentials` (List of Object) Credentials for the Application User (see [below for nested schema](#nestedblock--users--credentials))
44+
- `external_id` (String) The ID of the user in the target app that's linked to the Okta Application User object
45+
- `id` (String) Unique identifier for the Okta User
46+
- `last_sync` (String) Timestamp of the last synchronization operation
47+
- `last_updated` (String) Timestamp when the Application User was last updated
48+
- `password_changed` (String) Timestamp when the Application User password was last changed
49+
- `profile` (Map of String) Profile properties for the user in this application
50+
- `scope` (String) Indicates if the assignment is direct (USER) or by group membership (GROUP)
51+
- `status` (String) Status of an Application User
52+
- `status_changed` (String) Timestamp when the Application User status was last changed
53+
- `sync_state` (String) The synchronization state for the Application User
54+
55+
<a id="nestedblock--users--credentials"></a>
56+
57+
### Nested Schema for `users.credentials`
2958

59+
Read-Only:
3060

61+
- `password` (String, Sensitive) Password for the Application User
62+
- `user_name` (String) Username for the Application User

examples/data-sources/okta_app_user_assignments/datasource.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,24 @@ data "okta_app_user_assignments" "test" {
2424
depends_on = [okta_app_user.test]
2525
id = okta_app_oauth.test.id
2626
}
27+
28+
# Outputs to demonstrate the enhanced data source
29+
output "user_count" {
30+
description = "Number of users assigned to the app"
31+
value = length(data.okta_app_user_assignments.test.users)
32+
}
33+
34+
output "user_details" {
35+
description = "Detailed information about assigned users"
36+
value = data.okta_app_user_assignments.test.users
37+
}
38+
39+
output "first_user_status" {
40+
description = "Status of the first assigned user"
41+
value = length(data.okta_app_user_assignments.test.users) > 0 ? data.okta_app_user_assignments.test.users[0].status : null
42+
}
43+
44+
output "first_user_scope" {
45+
description = "Scope of the first assigned user (USER or GROUP)"
46+
value = length(data.okta_app_user_assignments.test.users) > 0 ? data.okta_app_user_assignments.test.users[0].scope : null
47+
}

okta/services/idaas/data_source_okta_app_user_assignments.go

Lines changed: 170 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,122 @@ package idaas
22

33
import (
44
"context"
5+
"fmt"
6+
"time"
57

68
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
79
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8-
"github.com/okta/terraform-provider-okta/okta/utils"
910
"github.com/okta/terraform-provider-okta/sdk"
1011
"github.com/okta/terraform-provider-okta/sdk/query"
1112
)
1213

14+
// dataSourceAppUserAssignments returns a Terraform data source for retrieving
15+
// detailed information about users assigned to an Okta application.
16+
// This data source exposes the full API response including user status, scope,
17+
// profile data, credentials, and timestamps.
1318
func dataSourceAppUserAssignments() *schema.Resource {
1419
return &schema.Resource{
1520
ReadContext: dataSourceAppUserAssignmentsRead,
1621
Schema: map[string]*schema.Schema{
1722
"id": {
1823
Type: schema.TypeString,
1924
Required: true,
20-
Description: "ID of the Okta App being queried for groups",
25+
Description: "ID of the Okta App being queried for users",
2126
ForceNew: true,
2227
},
2328
"users": {
2429
Type: schema.TypeSet,
2530
Computed: true,
26-
Elem: &schema.Schema{Type: schema.TypeString},
27-
Description: "List of user IDs assigned to the app",
31+
Description: "List of users assigned to the app with detailed information",
32+
Elem: &schema.Resource{
33+
Schema: map[string]*schema.Schema{
34+
"id": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
Description: "Unique identifier for the Okta User",
38+
},
39+
"external_id": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
Description: "The ID of the user in the target app that's linked to the Okta Application User object",
43+
},
44+
"status": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
Description: "Status of an Application User (ACTIVE, INACTIVE, PROVISIONED, etc.)",
48+
},
49+
"scope": {
50+
Type: schema.TypeString,
51+
Computed: true,
52+
Description: "Indicates if the assignment is direct (USER) or by group membership (GROUP)",
53+
},
54+
"sync_state": {
55+
Type: schema.TypeString,
56+
Computed: true,
57+
Description: "The synchronization state for the Application User (DISABLED, ENABLED, ERROR, etc.)",
58+
},
59+
"created": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
Description: "Timestamp when the Application User was created",
63+
},
64+
"last_updated": {
65+
Type: schema.TypeString,
66+
Computed: true,
67+
Description: "Timestamp when the Application User was last updated",
68+
},
69+
"last_sync": {
70+
Type: schema.TypeString,
71+
Computed: true,
72+
Description: "Timestamp of the last synchronization operation",
73+
},
74+
"password_changed": {
75+
Type: schema.TypeString,
76+
Computed: true,
77+
Description: "Timestamp when the Application User password was last changed",
78+
},
79+
"status_changed": {
80+
Type: schema.TypeString,
81+
Computed: true,
82+
Description: "Timestamp when the Application User status was last changed",
83+
},
84+
"profile": {
85+
Type: schema.TypeMap,
86+
Computed: true,
87+
Description: "Profile properties for the user in this application",
88+
Elem: &schema.Schema{Type: schema.TypeString},
89+
},
90+
"credentials": {
91+
Type: schema.TypeList,
92+
Computed: true,
93+
Description: "Credentials for the Application User",
94+
Elem: &schema.Resource{
95+
Schema: map[string]*schema.Schema{
96+
"user_name": {
97+
Type: schema.TypeString,
98+
Computed: true,
99+
Description: "Username for the Application User",
100+
},
101+
"password": {
102+
Type: schema.TypeString,
103+
Computed: true,
104+
Description: "Password for the Application User",
105+
Sensitive: true,
106+
},
107+
},
108+
},
109+
},
110+
},
111+
},
28112
},
29113
},
30-
Description: "Get a set of users assigned to an Okta application.",
114+
Description: "Get a set of users assigned to an Okta application with detailed information.",
31115
}
32116
}
33117

118+
// dataSourceAppUserAssignmentsRead retrieves all users assigned to an Okta application
119+
// and returns detailed information about each user including their status, scope,
120+
// profile data, credentials, and various timestamps.
34121
func dataSourceAppUserAssignmentsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
35122
client := getOktaClientFromMetadata(meta)
36123
id := d.Get("id").(string)
@@ -49,11 +136,86 @@ func dataSourceAppUserAssignmentsRead(ctx context.Context, d *schema.ResourceDat
49136
userAssignments = append(userAssignments, moreAssignments...)
50137
}
51138

52-
var users []string
139+
var users []map[string]interface{}
53140
for _, assignment := range userAssignments {
54-
users = append(users, assignment.Id)
141+
user := processAppUserAssignment(assignment)
142+
users = append(users, user)
55143
}
56-
_ = d.Set("users", utils.ConvertStringSliceToSet(users))
144+
145+
_ = d.Set("users", users)
57146
d.SetId(id)
58147
return nil
59148
}
149+
150+
// processAppUserAssignment converts an AppUser to a Terraform-compatible map
151+
func processAppUserAssignment(assignment *sdk.AppUser) map[string]interface{} {
152+
user := map[string]interface{}{
153+
"id": assignment.Id,
154+
}
155+
156+
if assignment.ExternalId != "" {
157+
user["external_id"] = assignment.ExternalId
158+
}
159+
if assignment.Status != "" {
160+
user["status"] = assignment.Status
161+
}
162+
if assignment.Scope != "" {
163+
user["scope"] = assignment.Scope
164+
}
165+
if assignment.SyncState != "" {
166+
user["sync_state"] = assignment.SyncState
167+
}
168+
if assignment.Created != nil {
169+
user["created"] = assignment.Created.Format(time.RFC3339)
170+
}
171+
if assignment.LastUpdated != nil {
172+
user["last_updated"] = assignment.LastUpdated.Format(time.RFC3339)
173+
}
174+
if assignment.LastSync != nil {
175+
user["last_sync"] = assignment.LastSync.Format(time.RFC3339)
176+
}
177+
if assignment.PasswordChanged != nil {
178+
user["password_changed"] = assignment.PasswordChanged.Format(time.RFC3339)
179+
}
180+
if assignment.StatusChanged != nil {
181+
user["status_changed"] = assignment.StatusChanged.Format(time.RFC3339)
182+
}
183+
184+
// Handle profile data
185+
if assignment.Profile != nil {
186+
if profileMap, ok := assignment.Profile.(map[string]interface{}); ok {
187+
// Convert profile values to strings for Terraform compatibility
188+
stringProfile := make(map[string]string)
189+
for k, v := range profileMap {
190+
if v == nil {
191+
continue // Skip null values
192+
}
193+
if str, ok := v.(string); ok {
194+
stringProfile[k] = str
195+
} else {
196+
// Convert other types to string representation
197+
stringProfile[k] = fmt.Sprintf("%v", v)
198+
}
199+
}
200+
if len(stringProfile) > 0 {
201+
user["profile"] = stringProfile
202+
}
203+
}
204+
}
205+
206+
// Handle credentials
207+
if assignment.Credentials != nil {
208+
credentials := map[string]interface{}{}
209+
if assignment.Credentials.UserName != "" {
210+
credentials["user_name"] = assignment.Credentials.UserName
211+
}
212+
if assignment.Credentials.Password != nil && assignment.Credentials.Password.Value != "" {
213+
credentials["password"] = assignment.Credentials.Password.Value
214+
}
215+
if len(credentials) > 0 {
216+
user["credentials"] = []map[string]interface{}{credentials}
217+
}
218+
}
219+
220+
return user
221+
}

okta/services/idaas/data_source_okta_app_user_assignments_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ func TestAccDataSourceOktaAppUserAssignments_read(t *testing.T) {
2020
Config: config,
2121
Check: resource.ComposeTestCheckFunc(
2222
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.#"),
23+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.id"),
24+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.status"),
25+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.scope"),
26+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.sync_state"),
27+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.created"),
28+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.last_updated"),
29+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.status_changed"),
30+
// Test that credentials are present when available
31+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.credentials.#"),
32+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.credentials.0.user_name"),
33+
// Test that profile data is present
34+
resource.TestCheckResourceAttrSet("data.okta_app_user_assignments.test", "users.0.profile.%"),
2335
),
2436
},
2537
},

0 commit comments

Comments
 (0)