Skip to content

Commit

Permalink
bug(iam): iam_member using groups API for assignment (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
ndopj authored Nov 1, 2023
1 parent a8c40ba commit fb2c1a7
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 242 deletions.
32 changes: 29 additions & 3 deletions monte_carlo/client/monte_carlo_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ type GetTables struct {
} `graphql:"getTables(dwId: $dwId, first: $first, after: $after, isDeleted: $isDeleted, isExcluded: $isExcluded)"`
}

type User struct {
type AuthorizationGroupUser struct {
CognitoUserId string
Email string
FirstName string
Expand All @@ -226,13 +226,13 @@ type AuthorizationGroup struct {
Roles []struct{ Name string }
DomainRestrictions []struct{ Uuid string }
SsoGroup *string
Users []User
Users []AuthorizationGroupUser
}

type CreateOrUpdateAuthorizationGroup struct {
CreateOrUpdateAuthorizationGroup struct {
AuthorizationGroup AuthorizationGroup
} `graphql:"createOrUpdateAuthorizationGroup(name: $name, label: $label, description: $description, roles: $roles, memberUserIds: $memberUserIds, domainRestrictionIds: $domainRestrictionIds, ssoGroup: $ssoGroup)"`
} `graphql:"createOrUpdateAuthorizationGroup(name: $name, label: $label, description: $description, roles: $roles, domainRestrictionIds: $domainRestrictionIds, ssoGroup: $ssoGroup)"`
}

type GetAuthorizationGroups struct {
Expand All @@ -245,6 +245,17 @@ type DeleteAuthorizationGroup struct {
} `graphql:"deleteAuthorizationGroup(name: $name)"`
}

type User struct {
CognitoUserId string
Email string
FirstName string
LastName string
IsSso bool
Auth struct {
Groups []string
}
}

type GetUsersInAccount struct {
GetUsersInAccount struct {
Edges []struct {
Expand All @@ -257,3 +268,18 @@ type GetUsersInAccount struct {
}
} `graphql:"getUsersInAccount(email: $email, first: $first, after: $after)"`
}

type UpdateUserAuthorizationGroupMembership struct {
UpdateUserAuthorizationGroupMembership struct {
AddedToGroups []struct {
Name string
Label string
Description string
}
RemovedFromGroups []struct {
Name string
Label string
Description string
}
} `graphql:"updateUserAuthorizationGroupMembership(memberUserId: $memberUserId, groupNames: $groupNames)"`
}
2 changes: 0 additions & 2 deletions monte_carlo/resources/iam_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ func (r *IamGroupResource) Create(ctx context.Context, req resource.CreateReques
"roles": []string{data.Role.ValueString()},
"domainRestrictionIds": normalize[client.UUID](data.Domains),
"ssoGroup": data.SsoGroup.ValueStringPointer(),
"memberUserIds": (*[]string)(nil),
}

if err := r.client.Mutate(ctx, &createResult, variables); err == nil {
Expand Down Expand Up @@ -187,7 +186,6 @@ func (r *IamGroupResource) Update(ctx context.Context, req resource.UpdateReques
"roles": []string{data.Role.ValueString()},
"domainRestrictionIds": normalize[client.UUID](data.Domains),
"ssoGroup": data.SsoGroup.ValueStringPointer(),
"memberUserIds": (*[]string)(nil),
}

if err := r.client.Mutate(ctx, &updateResult, variables); err == nil {
Expand Down
118 changes: 54 additions & 64 deletions monte_carlo/resources/iam_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ func (r *IamMemberResource) Create(ctx context.Context, req resource.CreateReque
return
}

groupName := strings.Split(data.Group.ValueString(), "groups/")[1]
getGroupResult := client.GetAuthorizationGroups{}
variables = map[string]interface{}{}
if err := r.client.Query(ctx, &getGroupResult, variables); err != nil {
Expand All @@ -120,39 +119,30 @@ func (r *IamMemberResource) Create(ctx context.Context, req resource.CreateReque
return
}

var found *client.AuthorizationGroup
var group *client.AuthorizationGroup
groupName := strings.Split(data.Group.ValueString(), "groups/")[1]
if index := slices.IndexFunc(getGroupResult.GetAuthorizationGroups, func(group client.AuthorizationGroup) bool {
return !group.IsManaged && group.Name == groupName
}); index >= 0 && getGroupResult.GetAuthorizationGroups[index].SsoGroup == nil {
found = &getGroupResult.GetAuthorizationGroups[index]
return group.SsoGroup == nil && group.Name == groupName
}); index >= 0 {
group = &getGroupResult.GetAuthorizationGroups[index]
} else {
to_print := fmt.Sprintf("Group %s not found or is SSO managed", data.Group.ValueString())
resp.Diagnostics.AddError(to_print, "")
return
}

memberUserIds := make([]string, len(found.Users)+1)
memberUserIds[len(found.Users)] = getUserResult.GetUsersInAccount.Edges[0].Node.CognitoUserId
for i, user := range found.Users {
memberUserIds[i] = user.CognitoUserId
}

updateResult := client.CreateOrUpdateAuthorizationGroup{}
user := &getUserResult.GetUsersInAccount.Edges[0].Node
updateResult := client.UpdateUserAuthorizationGroupMembership{}
variables = map[string]interface{}{
"name": found.Name,
"label": found.Label,
"description": found.Description,
"roles": rolesToNames(found.Roles),
"domainRestrictionIds": domainsToUuids[client.UUID](found.DomainRestrictions),
"ssoGroup": found.SsoGroup,
"memberUserIds": memberUserIds,
"memberUserId": user.CognitoUserId,
"groupNames": append(user.Auth.Groups, group.Name),
}

if err := r.client.Mutate(ctx, &updateResult, variables); err != nil {
to_print := fmt.Sprintf("MC client 'createOrUpdateAuthorizationGroup' mutation result - %s", err.Error())
to_print := fmt.Sprintf("MC client 'updateUserAuthorizationGroupMembership' mutation result - %s", err.Error())
resp.Diagnostics.AddError(to_print, "")
} else {
data.MemberId = types.StringValue(getUserResult.GetUsersInAccount.Edges[0].Node.CognitoUserId)
data.MemberId = types.StringValue(user.CognitoUserId)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
}
Expand All @@ -172,17 +162,20 @@ func (r *IamMemberResource) Read(ctx context.Context, req resource.ReadRequest,
"after": (*string)(nil),
}

var foundUser *client.User
if err := r.client.Query(ctx, &getUserResult, variables); err != nil {
to_print := fmt.Sprintf("MC client 'getUsersInAccount' query result - %s", err.Error())
resp.Diagnostics.AddError(to_print, "")
return
} else if len(getUserResult.GetUsersInAccount.Edges) == 0 {
} else if len(getUserResult.GetUsersInAccount.Edges) >= 1 {
foundUser = &getUserResult.GetUsersInAccount.Edges[0].Node
} else {
to_print := fmt.Sprintf("User %s not found", userEmail)
resp.Diagnostics.AddError(to_print, "")
resp.Diagnostics.AddWarning(to_print, "")
resp.State.RemoveResource(ctx)
return
}

groupName := strings.Split(data.Group.ValueString(), "groups/")[1]
getGroupResult := client.GetAuthorizationGroups{}
variables = map[string]interface{}{}
if err := r.client.Query(ctx, &getGroupResult, variables); err != nil {
Expand All @@ -191,20 +184,22 @@ func (r *IamMemberResource) Read(ctx context.Context, req resource.ReadRequest,
return
}

var found *client.AuthorizationGroup
for _, group := range getGroupResult.GetAuthorizationGroups {
if !group.IsManaged && group.Name == groupName {
found = &group
break
}
}

if found == nil || found.SsoGroup != nil {
var group *client.AuthorizationGroup
groupName := strings.Split(data.Group.ValueString(), "groups/")[1]
if index := slices.IndexFunc(getGroupResult.GetAuthorizationGroups, func(group client.AuthorizationGroup) bool {
return group.SsoGroup == nil && group.Name == groupName
}); index >= 0 {
group = &getGroupResult.GetAuthorizationGroups[index]
} else {
data.Group = types.StringNull()
to_print := fmt.Sprintf("Group %s not found or is SSO managed", data.Group.ValueString())
resp.Diagnostics.AddWarning(to_print, "")
resp.State.RemoveResource(ctx)
} else if !slices.Contains(found.Users, getUserResult.GetUsersInAccount.Edges[0].Node) {
to_print := fmt.Sprintf("User %s not found in group %s", userEmail, data.Group.ValueString())
return
}

if !slices.Contains(foundUser.Auth.Groups, group.Name) {
to_print := fmt.Sprintf("User %s is not a member of group %s", userEmail, data.Group.ValueString())
resp.Diagnostics.AddWarning(to_print, "")
resp.State.RemoveResource(ctx)
} else {
Expand All @@ -214,7 +209,10 @@ func (r *IamMemberResource) Read(ctx context.Context, req resource.ReadRequest,
}

func (r *IamMemberResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// TODO
resp.Diagnostics.AddError(
"Resource 'montecarlo_iam_member' does not support updates",
"If you encounter this error please raise a issue at 'https://github.com/kiwicom/terraform-provider-montecarlo'",
)
}

func (r *IamMemberResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
Expand All @@ -224,45 +222,37 @@ func (r *IamMemberResource) Delete(ctx context.Context, req resource.DeleteReque
return
}

groupName := strings.Split(data.Group.ValueString(), "groups/")[1]
getGroupResult := client.GetAuthorizationGroups{}
variables := map[string]interface{}{}
if err := r.client.Query(ctx, &getGroupResult, variables); err != nil {
to_print := fmt.Sprintf("MC client 'GetAuthorizationGroups' query result - %s", err.Error())
resp.Diagnostics.AddError(to_print, "")
return
userEmail := strings.Split(data.Member.ValueString(), "user:")[1]
getUserResult := client.GetUsersInAccount{}
variables := map[string]interface{}{
"email": userEmail,
"first": 1,
"after": (*string)(nil),
}

var found *client.AuthorizationGroup
if index := slices.IndexFunc(getGroupResult.GetAuthorizationGroups, func(group client.AuthorizationGroup) bool {
return !group.IsManaged && group.Name == groupName
}); index >= 0 && getGroupResult.GetAuthorizationGroups[index].SsoGroup == nil {
found = &getGroupResult.GetAuthorizationGroups[index]
var foundUser *client.User
if err := r.client.Query(ctx, &getUserResult, variables); err != nil {
to_print := fmt.Sprintf("MC client 'getUsersInAccount' query result - %s", err.Error())
resp.Diagnostics.AddError(to_print, "")
return
} else if len(getUserResult.GetUsersInAccount.Edges) >= 1 {
foundUser = &getUserResult.GetUsersInAccount.Edges[0].Node
} else {
to_print := fmt.Sprintf("Group %s not found or is SSO managed", data.Group.ValueString())
to_print := fmt.Sprintf("User %s not found", userEmail)
resp.Diagnostics.AddWarning(to_print, "")
return
}

memberUserIds := make([]string, len(found.Users))
for i, user := range found.Users {
memberUserIds[i] = user.CognitoUserId
}

updateResult := client.CreateOrUpdateAuthorizationGroup{}
memberUserIds = slices.DeleteFunc(memberUserIds, func(userId string) bool { return userId == data.MemberId.ValueString() })
updateResult := client.UpdateUserAuthorizationGroupMembership{}
variables = map[string]interface{}{
"name": found.Name,
"label": found.Label,
"description": found.Description,
"roles": rolesToNames(found.Roles),
"domainRestrictionIds": domainsToUuids[client.UUID](found.DomainRestrictions),
"ssoGroup": found.SsoGroup,
"memberUserIds": memberUserIds,
"memberUserId": foundUser.CognitoUserId,
"groupNames": slices.DeleteFunc(foundUser.Auth.Groups, func(groupName string) bool {
return groupName == strings.Split(data.Group.ValueString(), "groups/")[1]
}),
}

if err := r.client.Mutate(ctx, &updateResult, variables); err != nil {
to_print := fmt.Sprintf("MC client 'createOrUpdateAuthorizationGroup' mutation result - %s", err.Error())
to_print := fmt.Sprintf("MC client 'updateUserAuthorizationGroupMembership' mutation result - %s", err.Error())
resp.Diagnostics.AddError(to_print, "")
}
}
Expand Down
Loading

0 comments on commit fb2c1a7

Please sign in to comment.