Skip to content

Commit

Permalink
Merge pull request #393 from hashicorp/feature/group-mail-security
Browse files Browse the repository at this point in the history
azuread_group: add mail_enabled and security_enabled attributes
  • Loading branch information
manicminer authored Feb 8, 2021
2 parents aa3fef9 + 702ef0c commit d95c7a2
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 12 deletions.
20 changes: 12 additions & 8 deletions docs/data-sources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,30 @@ Gets information about an Azure Active Directory group.

```hcl
data "azuread_group" "example" {
display_name = "A-AD-Group"
display_name = "MyGroupName"
security_enabled = true
}
```

## Argument Reference

The following arguments are supported:

* `display_name` - (Optional) The splay name of the Group within Azure Active Directory.
* `object_id` - (Optional) Specifies the Object ID of the Group within Azure Active Directory.
* `display_name` - (Optional) The display name for the Group.
* `mail_enabled` - (Optional) Whether the group is mail-enabled.
* `object_id` - (Optional) Specifies the Object ID of the Group.
* `security_enabled` - (Optional) Whether the group is a security group.

~> **NOTE:** One of `display_name` or `object_id` must be specified.

## Attributes Reference

The following attributes are exported:

* `description` - The description of the AD Group.
* `display_name` - The name of the Azure AD Group.
* `description` - The optional description of the Group.
* `display_name` - The display name for the Group.
* `id` - The Object ID of the Azure AD Group.
* `members` - The Object IDs of the Azure AD Group members.
* `owners` - The Object IDs of the Azure AD Group owners.

* `mail_enabled` - Whether the group is mail-enabled.
* `members` - The Object IDs of the Group members.
* `owners` - The Object IDs of the Group owners.
* `security_enabled` - Whether the group is a security group.
4 changes: 4 additions & 0 deletions docs/resources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ The following arguments are supported:

In addition to all arguments above, the following attributes are exported:

* `mail_enabled` - Whether the group is mail-enabled.
* `object_id` - The Object ID of the Group.
* `security_enabled` - Whether the group is a security group.

~> **NOTE:** Due to API limitations, this resource only supports the creation of security-only groups.

## Import

Expand Down
10 changes: 9 additions & 1 deletion internal/helpers/aadgraph/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@ import (
"github.com/terraform-providers/terraform-provider-azuread/internal/utils"
)

func GroupGetByDisplayName(ctx context.Context, client *graphrbac.GroupsClient, displayName string) (*graphrbac.ADGroup, error) {
func GroupGetByDisplayName(ctx context.Context, client *graphrbac.GroupsClient, displayName string, mailEnabled *bool, securityEnabled *bool) (*graphrbac.ADGroup, error) {
filter := fmt.Sprintf("displayName eq '%s'", displayName)

if mailEnabled != nil {
filter = fmt.Sprintf("%s and mailEnabled eq %t", filter, *mailEnabled)
}

if securityEnabled != nil {
filter = fmt.Sprintf("%s and securityEnabled eq %t", filter, *securityEnabled)
}

resp, err := client.ListComplete(ctx, filter)
if err != nil {
return nil, fmt.Errorf("listing Groups for filter %q: %+v", filter, err)
Expand Down
55 changes: 53 additions & 2 deletions internal/services/groups/group_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package groups
import (
"context"
"errors"
"fmt"
"strings"

"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -54,6 +56,18 @@ func groupDataSource() *schema.Resource {
ValidateDiagFunc: validate.NoEmptyStrings,
},

"mail_enabled": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},

"security_enabled": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},

"members": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -81,6 +95,14 @@ func groupDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inter
name = v.(string)
}

var mailEnabled, securityEnabled *bool
if v, exists := d.GetOkExists("mail_enabled"); exists { //nolint:SA1019
mailEnabled = utils.Bool(v.(bool))
}
if v, exists := d.GetOkExists("security_enabled"); exists { //nolint:SA1019
securityEnabled = utils.Bool(v.(bool))
}

if objectId, ok := d.Get("object_id").(string); ok && objectId != "" {
resp, err := client.Get(ctx, objectId)
if err != nil {
Expand All @@ -91,11 +113,38 @@ func groupDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inter
return tf.ErrorDiagF(err, "Retrieving group with object ID: %q", objectId)
}

if mailEnabled != nil && (resp.MailEnabled == nil || *resp.MailEnabled != *mailEnabled) {
var actual string
if resp.MailEnabled == nil {
actual = "nil"
} else {
actual = fmt.Sprintf("%t", *resp.MailEnabled)
}
return tf.ErrorDiagPathF(nil, "mail_enabled", "Group with object ID %q does not have the specified mail_enabled setting (expected: %t, actual: %s)", objectId, *mailEnabled, actual)
}

if securityEnabled != nil && (resp.SecurityEnabled == nil || *resp.SecurityEnabled != *securityEnabled) {
var actual string
if resp.SecurityEnabled == nil {
actual = "nil"
} else {
actual = fmt.Sprintf("%t", *resp.SecurityEnabled)
}
return tf.ErrorDiagPathF(nil, "security_enabled", "Group with object ID %q does not have the specified security_enabled setting (expected: %t, actual: %s)", objectId, *securityEnabled, actual)
}

group = resp
} else if name != "" {
g, err := aadgraph.GroupGetByDisplayName(ctx, client, name)
g, err := aadgraph.GroupGetByDisplayName(ctx, client, name, mailEnabled, securityEnabled)
if err != nil {
return tf.ErrorDiagPathF(err, "name", "No group found with display name: %q", name)
params := []string{fmt.Sprintf("display_name: %q", name)}
if mailEnabled != nil {
params = append(params, fmt.Sprintf("mail_enabled: %t", *mailEnabled))
}
if securityEnabled != nil {
params = append(params, fmt.Sprintf("security_enabled: %t", *securityEnabled))
}
return tf.ErrorDiagPathF(err, "name", "No group found matching specified parameters (%s)", strings.Join(params, ", "))
}
group = *g
}
Expand All @@ -109,6 +158,8 @@ func groupDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inter
tf.Set(d, "object_id", group.ObjectID)
tf.Set(d, "display_name", group.DisplayName)
tf.Set(d, "name", group.DisplayName)
tf.Set(d, "mail_enabled", group.MailEnabled)
tf.Set(d, "security_enabled", group.SecurityEnabled)

description := ""
if v, ok := group.AdditionalProperties["description"]; ok {
Expand Down
49 changes: 49 additions & 0 deletions internal/services/groups/group_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ func TestAccGroupDataSource_byName(t *testing.T) {
},
})
}
func TestAccGroupDataSource_byNameWithSecurity(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_group", "test")

data.DataSourceTest(t, []resource.TestStep{
{
Config: GroupDataSource{}.nameSecurity(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("name").HasValue(fmt.Sprintf("acctestGroup-%d", data.RandomInteger)),
),
},
})
}

func TestAccGroupDataSource_byNameDeprecated(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_group", "test")
Expand Down Expand Up @@ -64,6 +76,19 @@ func TestAccGroupDataSource_byObjectId(t *testing.T) {
})
}

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

data.DataSourceTest(t, []resource.TestStep{
{
Config: GroupDataSource{}.objectIdSecurity(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("name").HasValue(fmt.Sprintf("acctestGroup-%d", data.RandomInteger)),
),
},
})
}

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

Expand Down Expand Up @@ -112,6 +137,18 @@ data "azuread_group" "test" {
`, GroupResource{}.basic(data))
}

func (GroupDataSource) nameSecurity(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_group" "test" {
display_name = azuread_group.test.name
mail_enabled = false
security_enabled = true
}
`, GroupResource{}.basic(data))
}

func (GroupDataSource) caseInsensitiveName(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
Expand All @@ -131,6 +168,18 @@ data "azuread_group" "test" {
`, GroupResource{}.basic(data))
}

func (GroupDataSource) objectIdSecurity(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_group" "test" {
object_id = azuread_group.test.object_id
mail_enabled = false
security_enabled = true
}
`, GroupResource{}.basic(data))
}

func (GroupDataSource) members(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
Expand Down
13 changes: 13 additions & 0 deletions internal/services/groups/group_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ func groupResource() *schema.Resource {
Optional: true,
},

"mail_enabled": {
Type: schema.TypeBool,
Computed: true,
},

"members": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -84,11 +89,17 @@ func groupResource() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},

"prevent_duplicate_names": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"security_enabled": {
Type: schema.TypeBool,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -196,6 +207,8 @@ func groupResourceRead(ctx context.Context, d *schema.ResourceData, meta interfa
tf.Set(d, "object_id", resp.ObjectID)
tf.Set(d, "display_name", resp.DisplayName)
tf.Set(d, "name", resp.DisplayName)
tf.Set(d, "mail_enabled", resp.MailEnabled)
tf.Set(d, "security_enabled", resp.SecurityEnabled)

description := ""
if v, ok := resp.AdditionalProperties["description"]; ok {
Expand Down
2 changes: 1 addition & 1 deletion internal/services/groups/groups_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func groupsDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inte
if len(names) > 0 {
expectedCount = len(names)
for _, name := range names {
g, err := aadgraph.GroupGetByDisplayName(ctx, client, name.(string))
g, err := aadgraph.GroupGetByDisplayName(ctx, client, name.(string), nil, nil)
if err != nil {
return tf.ErrorDiagPathF(err, "name", "No group found with display name: %q", name)
}
Expand Down

0 comments on commit d95c7a2

Please sign in to comment.