Skip to content

Commit

Permalink
azuread_user & azuread_users: add lookup by mail_nickname (#161)
Browse files Browse the repository at this point in the history
Fixes #160
  • Loading branch information
Joakim Bakke Hellum authored and katbyte committed Oct 17, 2019
1 parent 18d76ad commit 40fc897
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 9 deletions.
21 changes: 15 additions & 6 deletions azuread/data_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ func dataUser() *schema.Resource {
ConflictsWith: []string{"object_id"},
},

"mail_nickname": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validate.NoEmptyStrings,
ConflictsWith: []string{"object_id", "user_principal_name"},
},

"account_enabled": {
Type: schema.TypeBool,
Computed: true,
Expand All @@ -49,11 +57,6 @@ func dataUser() *schema.Resource {
Computed: true,
},

"mail_nickname": {
Type: schema.TypeString,
Computed: true,
},

"usage_location": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -80,8 +83,14 @@ func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Error finding Azure AD User with object ID %q: %+v", oId, err)
}
user = *u
} else if mailNickname, ok := d.Get("mail_nickname").(string); ok && mailNickname != "" {
u, err := graph.UserGetByMailNickname(&client, ctx, mailNickname)
if err != nil {
return fmt.Errorf("Error finding Azure AD User with email alias %q: %+v", mailNickname, err)
}
user = *u
} else {
return fmt.Errorf("one of `object_id` or `user_principal_name` must be supplied")
return fmt.Errorf("one of `object_id`, `user_principal_name` and `mail_nickname` must be supplied")
}

if user.ObjectID == nil {
Expand Down
32 changes: 32 additions & 0 deletions azuread/data_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ func TestAccAzureADUserDataSource_byObjectId(t *testing.T) {
})
}

func TestAccAzureADUserDataSource_byMailNickname(t *testing.T) {
dsn := "data.azuread_user.test"
id := tf.AccRandTimeInt()
password := "p@$$wR2" + acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAzureADUserDataSource_byMailNickname(id, password),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(dsn, "user_principal_name"),
resource.TestCheckResourceAttrSet(dsn, "account_enabled"),
resource.TestCheckResourceAttrSet(dsn, "display_name"),
resource.TestCheckResourceAttrSet(dsn, "mail_nickname"),
),
},
},
})
}

func testAccAzureADUserDataSource_byUserPrincipalName(id int, password string) string {
return fmt.Sprintf(`
%s
Expand All @@ -73,3 +95,13 @@ data "azuread_user" "test" {
}
`, testAccADUser_basic(id, password))
}

func testAccAzureADUserDataSource_byMailNickname(id int, password string) string {
return fmt.Sprintf(`
%s
data "azuread_user" "test" {
mail_nickname = "${azuread_user.test.mail_nickname}"
}
`, testAccADUser_basic(id, password))
}
26 changes: 25 additions & 1 deletion azuread/data_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ func dataUsers() *schema.Resource {
ValidateFunc: validate.NoEmptyStrings,
},
},

"mail_nicknames": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MinItems: 1,
ConflictsWith: []string{"object_ids", "user_principal_names"},
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
},
}
}
Expand Down Expand Up @@ -75,8 +87,17 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error {
}
users = append(users, *u)
}
} else if mailNicknames, ok := d.Get("mail_nicknames").([]interface{}); ok && len(mailNicknames) > 0 {
expectedCount = len(mailNicknames)
for _, v := range mailNicknames {
u, err := graph.UserGetByMailNickname(&client, ctx, v.(string))
if err != nil {
return fmt.Errorf("Error finding Azure AD User with email alias %q: %+v", v.(string), err)
}
users = append(users, *u)
}
} else {
return fmt.Errorf("one of `object_ids` or `user_principal_names` must be supplied")
return fmt.Errorf("one of `object_ids`, `user_principal_names` or `mail_nicknames` must be supplied")
}

if len(users) != expectedCount {
Expand All @@ -85,13 +106,15 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error {

upns := make([]string, 0, len(users))
oids := make([]string, 0, len(users))
mailNicknames := make([]string, 0, len(users))
for _, u := range users {
if u.ObjectID == nil || u.UserPrincipalName == nil {
return fmt.Errorf("User with nil ObjectId or UPN was found: %v", u)
}

oids = append(oids, *u.ObjectID)
upns = append(upns, *u.UserPrincipalName)
mailNicknames = append(mailNicknames, *u.MailNickname)
}

h := sha1.New()
Expand All @@ -102,5 +125,6 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error {
d.SetId("users#" + base64.URLEncoding.EncodeToString(h.Sum(nil)))
d.Set("object_ids", oids)
d.Set("user_principal_names", upns)
d.Set("mail_nicknames", mailNicknames)
return nil
}
31 changes: 31 additions & 0 deletions azuread/data_users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ func TestAccAzureADUsersDataSource_byObjectIds(t *testing.T) {
})
}

func TestAccAzureADUsersDataSource_byMailNicknames(t *testing.T) {
dsn := "data.azuread_users.test"
id := tf.AccRandTimeInt()
password := "p@$$wR2" + acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAzureADUsersDataSource_byMailNicknames(id, password),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dsn, "user_principal_names.#", "2"),
resource.TestCheckResourceAttr(dsn, "object_ids.#", "2"),
resource.TestCheckResourceAttr(dsn, "mail_nicknames.#", "2"),
),
},
},
})
}

func testAccAzureADUsersDataSource_byUserPrincipalNames(id int, password string) string {
return fmt.Sprintf(`
%s
Expand All @@ -69,3 +90,13 @@ data "azuread_users" "test" {
}
`, testAccADUser_threeUsersABC(id, password))
}

func testAccAzureADUsersDataSource_byMailNicknames(id int, password string) string {
return fmt.Sprintf(`
%s
data "azuread_users" "test" {
mail_nicknames = ["${azuread_user.testA.mail_nickname}", "${azuread_user.testB.mail_nickname}"]
}
`, testAccADUser_threeUsersABC(id, password))
}
26 changes: 26 additions & 0 deletions azuread/helpers/graph/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,29 @@ func UserGetByObjectId(client *graphrbac.UsersClient, ctx context.Context, objec

return &user, nil
}

func UserGetByMailNickname(client *graphrbac.UsersClient, ctx context.Context, mailNickname string) (*graphrbac.User, error) {
filter := fmt.Sprintf("startswith(mailNickname,'%s')", mailNickname)
resp, err := client.ListComplete(ctx, filter)
if err != nil {
return nil, fmt.Errorf("Error listing Azure AD Users for filter %q: %+v", filter, err)
}

values := resp.Response().Value
if values == nil {
return nil, fmt.Errorf("nil values for AD Users matching %q", filter)
}
if len(*values) == 0 {
return nil, fmt.Errorf("Found no AD Users matching %q", filter)
}
if len(*values) > 2 {
return nil, fmt.Errorf("Found multiple AD Users matching %q", filter)
}

user := (*values)[0]
if user.DisplayName == nil {
return nil, fmt.Errorf("nil DisplayName for AD Users matching %q", filter)
}

return &user, nil
}
4 changes: 3 additions & 1 deletion website/docs/d/user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ The following arguments are supported:

* `object_id` - (Optional) Specifies the Object ID of the Application within Azure Active Directory.

-> **NOTE:** Either a `user_principal_name` or an `object_id` must be specified.
* `mail_nickname` - (Optional) The email alias of the Azure AD User.

-> **NOTE:** Either `user_principal_name`, `object_id` or `mail_nickname` must be specified.

## Attributes Reference

Expand Down
5 changes: 4 additions & 1 deletion website/docs/d/users.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ The following arguments are supported:

* `object_ids` - (Optional) The Object IDs of the Azure AD Users.

-> **NOTE:** Either `user_principal_names` or `object_ids` must be specified.
* `mail_nicknames` - (Optional) The email aliases of the Azure AD Users.

-> **NOTE:** Either `user_principal_names`, `object_ids` or `mail_nicknames` must be specified.

## Attributes Reference

The following attributes are exported:

* `object_ids` - The Object IDs of the Azure AD Users.
* `user_principal_names` - The User Principal Names of the Azure AD Users.
* `mail_nicknames` - The email aliases of the Azure AD Users.

0 comments on commit 40fc897

Please sign in to comment.