Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azuread_user support for immutable_id property #207

Merged
merged 5 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions azuread/data_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ func dataUser() *schema.Resource {
Computed: true,
},

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

"mail": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -112,6 +117,7 @@ func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error {
d.Set("user_principal_name", user.UserPrincipalName)
d.Set("account_enabled", user.AccountEnabled)
d.Set("display_name", user.DisplayName)
d.Set("immutable_id", user.ImmutableID)
d.Set("mail", user.Mail)
d.Set("mail_nickname", user.MailNickname)
d.Set("usage_location", user.UsageLocation)
Expand Down
15 changes: 15 additions & 0 deletions azuread/helpers/p/p.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,25 @@ func Bool(input bool) *bool {
return &input
}

func BoolI(i interface{}) *bool {
b := i.(bool)
return &b
}

func Int32(input int32) *int32 {
return &input
}

func Int32I(i interface{}) *int32 {
i32 := i.(int32)
return &i32
}

func String(input string) *string {
return &input
}

func StringI(i interface{}) *string {
s := i.(string)
return &s
}
112 changes: 58 additions & 54 deletions azuread/resource_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ func resourceUser() *schema.Resource {
Computed: true,
},

"immutable_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "This must be specified if you are using a federated domain for the user's userPrincipalName (UPN) property when creating a new user account. " +
"It is used to associate an on-premises Active Directory user account with their Azure AD user object.",
},

"object_id": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -102,30 +110,30 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {
ctx := meta.(*ArmClient).StopContext

upn := d.Get("user_principal_name").(string)
displayName := d.Get("display_name").(string)
mailNickName := d.Get("mail_nickname").(string)
accountEnabled := d.Get("account_enabled").(bool)
password := d.Get("password").(string)
forcePasswordChange := d.Get("force_password_change").(bool)

//default mail nickname to the first part of the UPN (matches the portal)
if mailNickName == "" {
mailNickName = strings.Split(upn, "@")[0]
}

userCreateParameters := graphrbac.UserCreateParameters{
AccountEnabled: &accountEnabled,
DisplayName: &displayName,
AccountEnabled: p.BoolI(d.Get("account_enabled")),
DisplayName: p.StringI(d.Get("display_name")),
MailNickname: &mailNickName,
PasswordProfile: &graphrbac.PasswordProfile{
ForceChangePasswordNextLogin: &forcePasswordChange,
Password: &password,
ForceChangePasswordNextLogin: p.BoolI(d.Get("force_password_change")),
Password: p.StringI(d.Get("password")),
},
UserPrincipalName: &upn,
}

if v, ok := d.GetOk("usage_location"); ok {
userCreateParameters.UsageLocation = p.String(v.(string))
userCreateParameters.UsageLocation = p.StringI(v)
}

if v, ok := d.GetOk("immutable_id"); ok {
userCreateParameters.ImmutableID = p.StringI(v)
}

user, err := client.Create(ctx, userCreateParameters)
Expand All @@ -147,6 +155,46 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {
return resourceUserRead(d, meta)
}

func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).usersClient
ctx := meta.(*ArmClient).StopContext

var userUpdateParameters graphrbac.UserUpdateParameters

if d.HasChange("display_name") {
userUpdateParameters.DisplayName = p.StringI(d.Get("display_name"))
}

if d.HasChange("mail_nickname") {
userUpdateParameters.MailNickname = p.StringI(d.Get("mail_nickname"))
}

if d.HasChange("account_enabled") {
userUpdateParameters.AccountEnabled = p.BoolI(d.Get("account_enabled"))
}

if d.HasChange("password") {
userUpdateParameters.PasswordProfile = &graphrbac.PasswordProfile{
ForceChangePasswordNextLogin: p.BoolI(d.Get("force_password_change")),
Password: p.StringI(d.Get("password")),
}
}

if d.HasChange("usage_location") {
userUpdateParameters.UsageLocation = p.StringI(d.Get("usage_location"))
}

if d.HasChange("immutable_id") {
derek-burdick marked this conversation as resolved.
Show resolved Hide resolved
userUpdateParameters.ImmutableID = p.StringI(d.Get("immutable_id"))
}

if _, err := client.Update(ctx, d.Id(), userUpdateParameters); err != nil {
return fmt.Errorf("Error updating User with ID %q: %+v", d.Id(), err)
}

return resourceUserRead(d, meta)
}

func resourceUserRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).usersClient
ctx := meta.(*ArmClient).StopContext
Expand All @@ -170,58 +218,14 @@ func resourceUserRead(d *schema.ResourceData, meta interface{}) error {
d.Set("account_enabled", user.AccountEnabled)
d.Set("object_id", user.ObjectID)
d.Set("usage_location", user.UsageLocation)
d.Set("immutable_id", user.ImmutableID)

d.Set("onpremises_sam_account_name", user.AdditionalProperties["onPremisesSamAccountName"])
d.Set("onpremises_user_principal_name", user.AdditionalProperties["onPremisesUserPrincipalName"])

return nil
}

func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).usersClient
ctx := meta.(*ArmClient).StopContext

var userUpdateParameters graphrbac.UserUpdateParameters

if d.HasChange("display_name") {
displayName := d.Get("display_name").(string)
userUpdateParameters.DisplayName = p.String(displayName)
}

if d.HasChange("mail_nickname") {
mailNickName := d.Get("mail_nickname").(string)
userUpdateParameters.MailNickname = p.String(mailNickName)
}

if d.HasChange("account_enabled") {
accountEnabled := d.Get("account_enabled").(bool)
userUpdateParameters.AccountEnabled = p.Bool(accountEnabled)
}

if d.HasChange("password") {
password := d.Get("password").(string)
forcePasswordChange := d.Get("force_password_change").(bool)

passwordProfile := &graphrbac.PasswordProfile{
ForceChangePasswordNextLogin: &forcePasswordChange,
Password: &password,
}

userUpdateParameters.PasswordProfile = passwordProfile
}

if d.HasChange("usage_location") {
usageLocation := d.Get("usage_location").(string)
userUpdateParameters.UsageLocation = p.String(usageLocation)
}

if _, err := client.Update(ctx, d.Id(), userUpdateParameters); err != nil {
return fmt.Errorf("Error updating User with ID %q: %+v", d.Id(), err)
}

return resourceUserRead(d, meta)
}

func resourceUserDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).usersClient
ctx := meta.(*ArmClient).StopContext
Expand Down
4 changes: 4 additions & 0 deletions azuread/resource_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package azuread

import (
"fmt"
"strconv"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
Expand Down Expand Up @@ -65,6 +66,7 @@ func TestAccAzureADUser_complete(t *testing.T) {
resource.TestCheckResourceAttr(rn, "display_name", fmt.Sprintf("acctestUser-%d-Updated", id)),
resource.TestCheckResourceAttr(rn, "mail_nickname", fmt.Sprintf("acctestUser-%d-Updated", id)),
resource.TestCheckResourceAttr(rn, "account_enabled", "false"),
resource.TestCheckResourceAttr(rn, "immutable_id", strconv.Itoa(id)),
),
},
{
Expand Down Expand Up @@ -111,6 +113,7 @@ func TestAccAzureADUser_update(t *testing.T) {
resource.TestCheckResourceAttr(rn, "display_name", fmt.Sprintf("acctestUser-%d-Updated", id)),
resource.TestCheckResourceAttr(rn, "mail_nickname", fmt.Sprintf("acctestUser-%d-Updated", id)),
resource.TestCheckResourceAttr(rn, "account_enabled", "false"),
resource.TestCheckResourceAttr(rn, "immutable_id", strconv.Itoa(id)),
),
},
{
Expand Down Expand Up @@ -204,6 +207,7 @@ resource "azuread_user" "test" {
password = "%[2]s"
force_password_change = true
usage_location = "NO"
immutable_id = "%[1]d"
}
`, id, password)
}
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The following arguments are supported:

* `mail_nickname` - (Optional) The email alias of the Azure AD User.

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

## Attributes Reference

Expand All @@ -47,3 +47,4 @@ The following attributes are exported:
* `onpremises_sam_account_name` - The on premise sam account name of the Azure AD User.
* `onpremises_user_principal_name` - The on premise user principal name of the Azure AD User.
* `usage_location` - The usage location of the Azure AD User.
* `immutable_id` - The value used to associate an on-premises Active Directory user account with their Azure AD user object.
1 change: 1 addition & 0 deletions website/docs/r/user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following arguments are supported:
* `mail_nickname`- (Optional) The mail alias for the user. Defaults to the user name part of the User Principal Name.
* `password` - (Required) The password for the User. The password must satisfy minimum requirements as specified by the password policy. The maximum length is 256 characters.
* `force_password_change` - (Optional) `true` if the User is forced to change the password during the next sign-in. Defaults to `false`.
* `immutable_id` - (Optional) The value used to associate an on-premises Active Directory user account with their Azure AD user object. This must be specified if you are using a federated domain for the user's userPrincipalName (UPN) property when creating a new user account.
* `usage_location` - (Optional) The usage location of the User. Required for users that will be assigned licenses due to legal requirement to check for availability of services in countries. The usage location is a two letter country code (ISO standard 3166). Examples include: `NO`, `JP`, and `GB`. Cannot be reset to null once set.

## Attributes Reference
Expand Down