Skip to content

Commit

Permalink
Merge pull request #279 from terraform-providers/duplicate-name-detec…
Browse files Browse the repository at this point in the history
…tion

azuread_application & azuread_group: Duplicate name detection
  • Loading branch information
manicminer authored Jun 23, 2020
2 parents 86da1e7 + a02ba8e commit d2dfb01
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 0 deletions.
28 changes: 28 additions & 0 deletions azuread/helpers/graph/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,31 @@ func ApplicationAddOwners(client graphrbac.ApplicationsClient, ctx context.Conte

return nil
}

func ApplicationFindByName(client graphrbac.ApplicationsClient, ctx context.Context, name string) (*graphrbac.Application, error) {
nameFilter := fmt.Sprintf("displayName eq '%s'", name)
resp, err := client.List(ctx, nameFilter)

if err != nil {
return nil, fmt.Errorf("unable to list Applications with filter %q: %+v", nameFilter, err)
}

for _, app := range resp.Values() {
if *app.DisplayName == name {
return &app, nil
}
}

return nil, nil
}

func ApplicationCheckNameAvailability(client graphrbac.ApplicationsClient, ctx context.Context, name string) error {
existingApp, err := ApplicationFindByName(client, ctx, name)
if err != nil {
return err
}
if existingApp != nil {
return fmt.Errorf("existing Application with name %q (AppID: %q) was found and `prevent_duplicate_names` was specified", name, *existingApp.AppID)
}
return nil
}
28 changes: 28 additions & 0 deletions azuread/helpers/graph/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,31 @@ func GroupAddOwners(client graphrbac.GroupsClient, ctx context.Context, groupId

return nil
}

func GroupFindByName(client graphrbac.GroupsClient, ctx context.Context, name string) (*graphrbac.ADGroup, error) {
nameFilter := fmt.Sprintf("displayName eq '%s'", name)
resp, err := client.List(ctx, nameFilter)

if err != nil {
return nil, fmt.Errorf("unable to list Groups with filter %q: %+v", nameFilter, err)
}

for _, group := range resp.Values() {
if *group.DisplayName == name {
return &group, nil
}
}

return nil, nil
}

func GroupCheckNameAvailability(client graphrbac.GroupsClient, ctx context.Context, name string) error {
existingGroup, err := GroupFindByName(client, ctx, name)
if err != nil {
return err
}
if existingGroup != nil {
return fmt.Errorf("existing Azure Active Directory Group with name %q (ObjID: %q) was found and `prevent_duplicate_names` was specified", name, *existingGroup.ObjectID)
}
return nil
}
24 changes: 24 additions & 0 deletions azuread/resource_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ func resourceApplication() *schema.Resource {
},
},
},
"prevent_duplicate_names": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}
Expand All @@ -294,6 +299,14 @@ func resourceApplicationCreate(d *schema.ResourceData, meta interface{}) error {
ctx := meta.(*ArmClient).StopContext

name := d.Get("name").(string)

if d.Get("prevent_duplicate_names").(bool) {
err := graph.ApplicationCheckNameAvailability(client, ctx, name)
if err != nil {
return err
}
}

appType := d.Get("type")
identUrls, hasIdentUrls := d.GetOk("identifier_uris")
if appType == "native" {
Expand Down Expand Up @@ -400,6 +413,13 @@ func resourceApplicationUpdate(d *schema.ResourceData, meta interface{}) error {

name := d.Get("name").(string)

if d.Get("prevent_duplicate_names").(bool) {
err := graph.ApplicationCheckNameAvailability(client, ctx, name)
if err != nil {
return err
}
}

var properties graphrbac.ApplicationUpdateParameters

if d.HasChange("name") {
Expand Down Expand Up @@ -591,6 +611,10 @@ func resourceApplicationRead(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("setting `owners`: %+v", err)
}

if preventDuplicates := d.Get("prevent_duplicate_names").(bool); !preventDuplicates {
d.Set("prevent_duplicate_names", false)
}

return nil
}

Expand Down
27 changes: 27 additions & 0 deletions azuread/resource_application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,22 @@ func TestAccAzureADApplication_oauth2PermissionsUpdate(t *testing.T) {
})
}

func TestAccAzureADApplication_preventDuplicateNames(t *testing.T) {
ri := tf.AccRandTimeInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckADApplicationDestroy,
Steps: []resource.TestStep{
{
Config: testAccADApplication_duplicateName(ri),
ExpectError: regexp.MustCompile("existing Application .+ was found"),
},
},
})
}

func testCheckADApplicationExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
Expand Down Expand Up @@ -913,3 +929,14 @@ resource "azuread_application" "test" {
}
`, ri)
}

func testAccADApplication_duplicateName(ri int) string {
return fmt.Sprintf(`
%s
resource "azuread_application" "duplicate" {
name = azuread_application.test.name
prevent_duplicate_names = true
}
`, testAccADApplication_basic(ri))
}
16 changes: 16 additions & 0 deletions azuread/resource_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ func resourceGroup() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"prevent_duplicate_names": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}
Expand All @@ -78,6 +83,13 @@ func resourceGroupCreate(d *schema.ResourceData, meta interface{}) error {

name := d.Get("name").(string)

if d.Get("prevent_duplicate_names").(bool) {
err := graph.GroupCheckNameAvailability(client, ctx, name)
if err != nil {
return err
}
}

properties := graphrbac.GroupCreateParameters{
DisplayName: &name,
MailEnabled: p.Bool(false), // we're defaulting to false, as the API currently only supports the creation of non-mail enabled security groups.
Expand Down Expand Up @@ -168,6 +180,10 @@ func resourceGroupRead(d *schema.ResourceData, meta interface{}) error {
}
d.Set("owners", owners)

if preventDuplicates := d.Get("prevent_duplicate_names").(bool); !preventDuplicates {
d.Set("prevent_duplicate_names", false)
}

return nil
}

Expand Down
28 changes: 28 additions & 0 deletions azuread/resource_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package azuread

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
Expand Down Expand Up @@ -286,6 +287,22 @@ func TestAccAzureADGroup_ownersUpdate(t *testing.T) {
})
}

func TestAccAzureADGroup_preventDuplicateNames(t *testing.T) {
ri := tf.AccRandTimeInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckADApplicationDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureADGroup_duplicateName(ri),
ExpectError: regexp.MustCompile("existing Azure Active Directory Group .+ was found"),
},
},
})
}

func testCheckAzureADGroupExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
Expand Down Expand Up @@ -503,3 +520,14 @@ resource "azuread_group" "test" {
}
`, id)
}

func testAccAzureADGroup_duplicateName(id int) string {
return fmt.Sprintf(`
%s
resource "azuread_group" "duplicate" {
name = azuread_group.test.name
prevent_duplicate_names = true
}
`, testAccAzureADGroup_basic(id))
}
2 changes: 2 additions & 0 deletions website/docs/r/application.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ The following arguments are supported:

* `oauth2_permissions` - (Optional) A collection of OAuth 2.0 permission scopes that the web API (resource) app exposes to client apps. Each permission is covered by `oauth2_permissions` blocks as documented below.

* `prevent_duplicate_names` - (Optional) If `true`, will return an error when an existing Application is found with the same name. Defaults to `false`.

---

`required_resource_access` supports the following:
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/group.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The following arguments are supported:
* `description` - (Optional) The description for the Group. Changing this forces a new resource to be created.
* `members` (Optional) A set of members who should be present in this Group. Supported Object types are Users, Groups or Service Principals.
* `owners` (Optional) A set of owners who own this Group. Supported Object types are Users or Service Principals.
* `prevent_duplicate_names` - (Optional) If `true`, will return an error when an existing Group is found with the same name. Defaults to `false`.

-> **NOTE:** Group names are not unique within Azure Active Directory.

Expand Down

0 comments on commit d2dfb01

Please sign in to comment.