Skip to content

Commit dd3336d

Browse files
authored
Merge pull request #306 from aquasecurity/SAAS-28333-tp-fix-aquasec-role-mapping-sass-resource-and-datasource
Refactor aquasec_role_mapping_sass (resource and datasource), Refactor sso.go
2 parents 5f6d335 + d9843bb commit dd3336d

File tree

9 files changed

+417
-362
lines changed

9 files changed

+417
-362
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package aquasec
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9+
)
10+
11+
func TestAquasecRolesMappingSaasDatasource(t *testing.T) {
12+
if !isSaasEnv() {
13+
t.Skip("Skipping SaaS roles mapping data source test - not a SaaS environment")
14+
}
15+
16+
resource.Test(t, resource.TestCase{
17+
PreCheck: func() { testAccPreCheck(t) },
18+
Providers: testAccProviders,
19+
Steps: []resource.TestStep{
20+
{
21+
Config: testAccCheckAquasecRolesMappingSaasBasicConfig(),
22+
Check: resource.ComposeTestCheckFunc(
23+
testAccCheckAquasecRolesMappingSaasExists("data.aquasec_roles_mapping_saas.test"),
24+
resource.TestCheckResourceAttrSet("data.aquasec_roles_mapping_saas.test", "roles_mapping.#"),
25+
),
26+
},
27+
},
28+
})
29+
}
30+
31+
func testAccCheckAquasecRolesMappingSaasBasicConfig() string {
32+
return `
33+
data "aquasec_roles_mapping_saas" "test" {}
34+
`
35+
}
36+
37+
func testAccCheckAquasecRolesMappingSaasExists(n string) resource.TestCheckFunc {
38+
return func(s *terraform.State) error {
39+
rs, ok := s.RootModule().Resources[n]
40+
if !ok {
41+
return fmt.Errorf("Not found: %s", n)
42+
}
43+
if rs.Primary.ID == "" {
44+
return fmt.Errorf("No ID is set for %s", n)
45+
}
46+
return nil
47+
}
48+
}

aquasec/data_role_mapping_sass.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func dataRolesMappingSaasRead(ctx context.Context, d *schema.ResourceData, m int
6060
} else {
6161
return diag.FromErr(err)
6262
}
63+
d.SetId("aquasec_roles_mapping_saas_list")
6364
return nil
6465
}
6566

aquasec/resource_role.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func resourceRoleRead(d *schema.ResourceData, m interface{}) error {
8787
return err
8888
}
8989

90-
d.Set("name", r.Name)
90+
d.Set("role_name", r.Name)
9191
d.Set("updated_at", r.UpdatedAt)
9292
d.Set("author", r.Author)
9393
d.Set("role_name", r.Name)

aquasec/resource_role_mapping_saas.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,34 @@ func resourceRoleMappingSaasRead(ctx context.Context, d *schema.ResourceData, m
5353
ac := m.(*client.Client)
5454

5555
r, err := ac.GetRoleMappingSaas(d.Id())
56-
if err == nil {
57-
d.Set("role_mapping_id", r.Id)
58-
d.Set("created", r.Created)
59-
d.Set("account_id", r.AccountId)
60-
} else {
56+
if err != nil {
6157
if strings.Contains(err.Error(), "404") {
6258
d.SetId("")
63-
} else {
64-
return diag.FromErr(err)
59+
return nil
6560
}
61+
return diag.FromErr(err)
62+
}
63+
64+
if err := d.Set("role_mapping_id", r.Id); err != nil {
65+
return diag.FromErr(err)
66+
}
67+
if err := d.Set("created", r.Created); err != nil {
68+
return diag.FromErr(err)
69+
}
70+
if err := d.Set("account_id", r.AccountId); err != nil {
71+
return diag.FromErr(err)
72+
}
73+
if err := d.Set("csp_role", r.CspRole); err != nil {
74+
return diag.FromErr(err)
6675
}
76+
if err := d.Set("saml_groups", r.SamlGroups); err != nil {
77+
return diag.FromErr(err)
78+
}
79+
6780
return nil
6881
}
6982

83+
7084
func resourceRoleMappingSaasCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
7185
c := m.(*client.Client)
7286

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package aquasec
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/aquasecurity/terraform-provider-aquasec/client"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11+
)
12+
13+
const (
14+
testRoleMappingSaasResourceName = "aquasec_role_mapping_saas.test"
15+
)
16+
17+
func TestAccAquasecRoleMappingSaas_basic(t *testing.T) {
18+
if !isSaasEnv() {
19+
t.Skip("Skipping role mapping SaaS test - not a SaaS environment")
20+
}
21+
22+
roleName := acctest.RandomWithPrefix("tf-role")
23+
permSetName := acctest.RandomWithPrefix("tf-pset")
24+
samlGroups := []string{"DevTeam", "SecTeam"}
25+
26+
resource.Test(t, resource.TestCase{
27+
PreCheck: func() { testAccPreCheck(t) },
28+
Providers: testAccProviders,
29+
CheckDestroy: testAccCheckRoleMappingSaasDestroy,
30+
Steps: []resource.TestStep{
31+
{
32+
Config: testAccRoleMappingSaasConfig(permSetName, roleName, samlGroups),
33+
Check: resource.ComposeTestCheckFunc(
34+
testAccCheckRoleMappingSaasExists(testRoleMappingSaasResourceName),
35+
resource.TestCheckResourceAttr(testRoleMappingSaasResourceName, "csp_role", roleName),
36+
resource.TestCheckResourceAttr(testRoleMappingSaasResourceName, "saml_groups.#", "2"),
37+
),
38+
},
39+
{
40+
ResourceName: testRoleMappingSaasResourceName,
41+
ImportState: true,
42+
ImportStateVerify: true,
43+
},
44+
},
45+
})
46+
}
47+
48+
func testAccRoleMappingSaasConfig(permSetName, roleName string, groups []string) string {
49+
groupsStr := ""
50+
for _, g := range groups {
51+
groupsStr += fmt.Sprintf("\"%s\", ", g)
52+
}
53+
groupsStr = groupsStr[:len(groupsStr)-2]
54+
55+
return fmt.Sprintf(`
56+
resource "aquasec_permission_set_saas" "ps" {
57+
name = "%s"
58+
description = "TF-generated permission set"
59+
actions = ["account_mgmt.groups.read"]
60+
}
61+
62+
resource "aquasec_role" "r" {
63+
role_name = "%s"
64+
description = "TF-generated role"
65+
permission = aquasec_permission_set_saas.ps.name
66+
scopes = ["Global"]
67+
}
68+
69+
resource "aquasec_role_mapping_saas" "test" {
70+
saml_groups = [%s]
71+
csp_role = aquasec_role.r.role_name
72+
}
73+
`, permSetName, roleName, groupsStr)
74+
}
75+
76+
func testAccCheckRoleMappingSaasExists(n string) resource.TestCheckFunc {
77+
return func(s *terraform.State) error {
78+
rs, ok := s.RootModule().Resources[n]
79+
if !ok {
80+
return fmt.Errorf("Resource not found in state: %s", n)
81+
}
82+
if rs.Primary.ID == "" {
83+
return fmt.Errorf("ID not set for resource: %s", n)
84+
}
85+
cli := testAccProvider.Meta().(*client.Client)
86+
_, err := cli.GetRoleMappingSaas(rs.Primary.ID)
87+
return err
88+
}
89+
}
90+
91+
func testAccCheckRoleMappingSaasDestroy(s *terraform.State) error {
92+
cli := testAccProvider.Meta().(*client.Client)
93+
for _, rs := range s.RootModule().Resources {
94+
if rs.Type != "aquasec_role_mapping_saas" {
95+
continue
96+
}
97+
_, err := cli.GetRoleMappingSaas(rs.Primary.ID)
98+
if err == nil {
99+
return fmt.Errorf("role mapping %q still exists", rs.Primary.ID)
100+
}
101+
}
102+
return nil
103+
}

client/role_mapping_saas.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
8+
"github.com/pkg/errors"
9+
10+
)
11+
12+
type RoleMappingSaas struct {
13+
CspRole string `json:"csp_role"`
14+
SamlGroups []string `json:"saml_groups"`
15+
Id int `json:"id"`
16+
Created string `json:"created"`
17+
AccountId int `json:"account_id"`
18+
}
19+
20+
type RoleMappingSaasList struct {
21+
Items []RoleMappingSaas `json:"data"`
22+
}
23+
24+
type RoleMappingSaasResponse struct {
25+
RoleMappingSaas RoleMappingSaas `json:"data"`
26+
}
27+
28+
const roleMappingBasePath = "/api/cspm/v2/samlmappings"
29+
30+
func (cli *Client) GetRoleMappingSaas(id string) (*RoleMappingSaas, error) {
31+
if cli.clientType != Saas && cli.clientType != SaasDev {
32+
return nil, fmt.Errorf("GetRoleMappingSaas is supported only in Aqua SaaS environment")
33+
}
34+
35+
if err := cli.limiter.Wait(context.Background()); err != nil {
36+
return nil, err
37+
}
38+
39+
url := fmt.Sprintf("%s%s/%s", cli.saasUrl, roleMappingBasePath, id)
40+
resp, body, errs := cli.gorequest.Clone().Get(url).
41+
Set("Authorization", fmt.Sprintf(authHeaderFormat, cli.token)).End()
42+
43+
if len(errs) > 0 {
44+
return nil, fmt.Errorf("failed GET %s: %v", url, errs)
45+
}
46+
if resp.StatusCode != statusOK {
47+
return nil, fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, body)
48+
}
49+
50+
var result RoleMappingSaasResponse
51+
if err := json.Unmarshal([]byte(body), &result); err != nil {
52+
return nil, errors.Wrap(err, "failed to unmarshal RoleMappingSaas response")
53+
}
54+
return &result.RoleMappingSaas, nil
55+
}
56+
57+
func (cli *Client) GetRolesMappingSaas() (*RoleMappingSaasList, error) {
58+
if cli.clientType != Saas && cli.clientType != SaasDev {
59+
return nil, fmt.Errorf("GetRolesMappingSaas is supported only in Aqua SaaS environment")
60+
}
61+
62+
if err := cli.limiter.Wait(context.Background()); err != nil {
63+
return nil, err
64+
}
65+
66+
url := fmt.Sprintf("%s%s", cli.saasUrl, roleMappingBasePath)
67+
resp, body, errs := cli.gorequest.Clone().Get(url).
68+
Set("Authorization", fmt.Sprintf(authHeaderFormat, cli.token)).End()
69+
70+
if len(errs) > 0 {
71+
return nil, fmt.Errorf("failed GET %s: %v", url, errs)
72+
}
73+
if resp.StatusCode != statusOK {
74+
return nil, fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, body)
75+
}
76+
77+
var result RoleMappingSaasList
78+
if err := json.Unmarshal([]byte(body), &result); err != nil {
79+
return nil, errors.Wrap(err, "failed to unmarshal RoleMappingSaas list")
80+
}
81+
return &result, nil
82+
}
83+
84+
func (cli *Client) CreateRoleMappingSaas(saas *RoleMappingSaas) error {
85+
if cli.clientType != Saas && cli.clientType != SaasDev {
86+
return fmt.Errorf("CreateRoleMappingSaas is supported only in Aqua SaaS environment")
87+
}
88+
89+
if err := cli.limiter.Wait(context.Background()); err != nil {
90+
return err
91+
}
92+
93+
url := fmt.Sprintf("%s%s", cli.saasUrl, roleMappingBasePath)
94+
saasPayload := map[string]interface{}{
95+
"csp_role": saas.CspRole,
96+
"saml_groups": saas.SamlGroups,
97+
}
98+
payload, _ := json.Marshal(saasPayload)
99+
100+
resp, body, errs := cli.gorequest.Clone().Post(url).
101+
Set("Authorization", fmt.Sprintf(authHeaderFormat, cli.token)).
102+
Send(string(payload)).End()
103+
104+
if len(errs) > 0 {
105+
return fmt.Errorf("failed POST %s: %v", url, errs)
106+
}
107+
if resp.StatusCode != statusCreated {
108+
return fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, body)
109+
}
110+
111+
var response RoleMappingSaasResponse
112+
if err := json.Unmarshal([]byte(body), &response); err != nil {
113+
return errors.Wrap(err, "failed to unmarshal response after creation")
114+
}
115+
saas.Id = response.RoleMappingSaas.Id
116+
saas.Created = response.RoleMappingSaas.Created
117+
saas.AccountId = response.RoleMappingSaas.AccountId
118+
return nil
119+
}
120+
121+
func (cli *Client) UpdateRoleMappingSaas(saas *RoleMappingSaas, id string) error {
122+
if cli.clientType != Saas && cli.clientType != SaasDev {
123+
return fmt.Errorf("UpdateRoleMappingSaas is supported only in Aqua SaaS environment")
124+
}
125+
126+
if err := cli.limiter.Wait(context.Background()); err != nil {
127+
return err
128+
}
129+
130+
url := fmt.Sprintf("%s%s/%s", cli.saasUrl, roleMappingBasePath, id)
131+
payloadMap := map[string]interface{}{
132+
"saml_groups": saas.SamlGroups,
133+
}
134+
payload, _ := json.Marshal(payloadMap)
135+
136+
resp, body, errs := cli.gorequest.Clone().Put(url).
137+
Set("Authorization", fmt.Sprintf(authHeaderFormat, cli.token)).
138+
Send(string(payload)).End()
139+
140+
if len(errs) > 0 {
141+
return fmt.Errorf("failed PUT %s: %v", url, errs)
142+
}
143+
if resp.StatusCode != statusNoContent {
144+
return fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, body)
145+
}
146+
return nil
147+
}
148+
149+
func (cli *Client) DeleteRoleMappingSaas(id string) error {
150+
if cli.clientType != Saas && cli.clientType != SaasDev {
151+
return fmt.Errorf("DeleteRoleMappingSaas is supported only in Aqua SaaS environment")
152+
}
153+
154+
if err := cli.limiter.Wait(context.Background()); err != nil {
155+
return err
156+
}
157+
158+
url := fmt.Sprintf("%s%s/%s", cli.saasUrl, roleMappingBasePath, id)
159+
resp, body, errs := cli.gorequest.Clone().Delete(url).
160+
Set("Authorization", fmt.Sprintf(authHeaderFormat, cli.token)).End()
161+
162+
if len(errs) > 0 {
163+
return fmt.Errorf("failed DELETE %s: %v", url, errs)
164+
}
165+
if resp.StatusCode != statusOK {
166+
return fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, body)
167+
}
168+
return nil
169+
}

0 commit comments

Comments
 (0)