Skip to content

Commit

Permalink
Merge pull request #1300 from TomasKunka/feat/transitive-members
Browse files Browse the repository at this point in the history
Feature: #881 Enable azuread_group to return indirect members
  • Loading branch information
manicminer authored May 8, 2024
2 parents c959313 + e442cee commit 7ee41ff
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 4 deletions.
3 changes: 2 additions & 1 deletion docs/data-sources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ data "azuread_group" "example" {
The following arguments are supported:

* `display_name` - (Optional) The display name for the group.
* `include_transitive_members` - (Optional) Whether to include transitive members (a flat list of all nested members). Defaults to `false`.
* `mail_nickname` - (Optional) The mail alias for the group, unique in the organisation.
* `mail_enabled` - (Optional) Whether the group is mail-enabled.
* `object_id` - (Optional) Specifies the object ID of the group.
Expand All @@ -52,7 +53,7 @@ The following attributes are exported:
* `mail` - The SMTP address for the group.
* `mail_enabled` - Whether the group is mail-enabled.
* `mail_nickname` - The mail alias for the group, unique in the organisation.
* `members` - List of object IDs of the group members.
* `members` - List of object IDs of the group members. When `include_transitive_members` is `true`, contains a list of object IDs of all transitive group members.
* `onpremises_domain_name` - The on-premises FQDN, also called dnsDomainName, synchronised from the on-premises directory when Azure AD Connect is used.
* `onpremises_group_type` - The on-premises group type that the AAD group will be written as, when writeback is enabled. Possible values are `UniversalDistributionGroup`, `UniversalMailEnabledSecurityGroup`, or `UniversalSecurityGroup`.
* `onpremises_netbios_name` - The on-premises NetBIOS name, synchronised from the on-premises directory when Azure AD Connect is used.
Expand Down
23 changes: 20 additions & 3 deletions internal/services/groups/group_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ func groupDataSource() *pluginsdk.Resource {
Computed: true,
},

"include_transitive_members": {
Description: "Specifies whether to include transitive members (a flat list of all nested members).",
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},

"assignable_to_role": {
Description: "Indicates whether this group can be assigned to an Azure Active Directory role",
Type: pluginsdk.TypeBool,
Expand Down Expand Up @@ -423,9 +430,19 @@ func groupDataSourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta in
tf.Set(d, "hide_from_address_lists", hideFromAddressLists)
tf.Set(d, "hide_from_outlook_clients", hideFromOutlookClients)

members, _, err := client.ListMembers(ctx, d.Id())
if err != nil {
return tf.ErrorDiagF(err, "Could not retrieve group members for group with object ID: %q", d.Id())
includeTransitiveMembers := d.Get("include_transitive_members").(bool)
var members *[]string
var err error
if includeTransitiveMembers {
members, _, err = client.ListTransitiveMembers(ctx, d.Id())
if err != nil {
return tf.ErrorDiagF(err, "Could not retrieve transitive group members for group with object ID: %q", d.Id())
}
} else {
members, _, err = client.ListMembers(ctx, d.Id())
if err != nil {
return tf.ErrorDiagF(err, "Could not retrieve group members for group with object ID: %q", d.Id())
}
}
tf.Set(d, "members", members)

Expand Down
25 changes: 25 additions & 0 deletions internal/services/groups/group_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,20 @@ func TestAccGroupDataSource_members(t *testing.T) {
})
}

func TestAccGroupDataSource_transitiveMembers(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_group", "test")

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: GroupDataSource{}.transitiveMembers(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("display_name").HasValue(fmt.Sprintf("acctestGroup-%d", data.RandomInteger)),
check.That(data.ResourceName).Key("members.#").HasValue("4"),
),
},
})
}

func TestAccGroupDataSource_owners(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_group", "test")

Expand Down Expand Up @@ -314,6 +328,17 @@ data "azuread_group" "test" {
`, GroupResource{}.withThreeMembers(data))
}

func (GroupDataSource) transitiveMembers(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_group" "test" {
object_id = azuread_group.test.object_id
include_transitive_members = true
}
`, GroupResource{}.withTransitiveMembers(data))
}

func (GroupDataSource) dynamicMembership(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
Expand Down
24 changes: 24 additions & 0 deletions internal/services/groups/group_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,30 @@ resource "azuread_group" "test" {
`, r.templateThreeUsers(data), data.RandomInteger)
}

func (r GroupResource) withTransitiveMembers(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
resource "azuread_group" "nested" {
display_name = "acctestGroup-%[2]d-Nested"
security_enabled = true
members = [
azuread_user.test.object_id,
azuread_group.member.object_id,
azuread_service_principal.test.object_id
]
}
resource "azuread_group" "test" {
display_name = "acctestGroup-%[2]d"
security_enabled = true
members = [
azuread_group.nested.object_id
]
}
`, r.templateDiverseDirectoryObjects(data), data.RandomInteger)
}

func (r GroupResource) withOwnersAndMembers(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
Expand Down

0 comments on commit 7ee41ff

Please sign in to comment.