diff --git a/plugins/security/api_actiongroups-delete.go b/plugins/security/api_actiongroups-delete.go new file mode 100644 index 000000000..fc89b3989 --- /dev/null +++ b/plugins/security/api_actiongroups-delete.go @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. + +package security + +import ( + "fmt" + "net/http" + + "github.com/opensearch-project/opensearch-go/v3" +) + +// ActionGroupsDeleteReq represents possible options for the actiongroups delete request +type ActionGroupsDeleteReq struct { + ActionGroup string + + Header http.Header +} + +// GetRequest returns the *http.Request that gets executed by the client +func (r ActionGroupsDeleteReq) GetRequest() (*http.Request, error) { + return opensearch.BuildRequest( + "DELETE", + fmt.Sprintf("/_plugins/_security/api/actiongroups/%s", r.ActionGroup), + nil, + make(map[string]string), + r.Header, + ) +} + +// ActionGroupsDeleteResp represents the returned struct of the actiongroups delete response +type ActionGroupsDeleteResp struct { + Status string `json:"status"` + Message string `json:"message"` + response *opensearch.Response +} + +// Inspect returns the Inspect type containing the raw *opensearch.Reponse +func (r ActionGroupsDeleteResp) Inspect() Inspect { + return Inspect{Response: r.response} +} diff --git a/plugins/security/api_actiongroups-get.go b/plugins/security/api_actiongroups-get.go new file mode 100644 index 000000000..5b8fd07b1 --- /dev/null +++ b/plugins/security/api_actiongroups-get.go @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. + +package security + +import ( + "net/http" + "strings" + + "github.com/opensearch-project/opensearch-go/v3" +) + +// ActionGroupsGetReq represents possible options for the actiongroups get request +type ActionGroupsGetReq struct { + Header http.Header + ActionGroup string +} + +// GetRequest returns the *http.Request that gets executed by the client +func (r ActionGroupsGetReq) GetRequest() (*http.Request, error) { + var path strings.Builder + path.Grow(len("/_plugins/_security/api/actiongroups/") + len(r.ActionGroup)) + path.WriteString("/_plugins/_security/api/actiongroups") + if len(r.ActionGroup) > 0 { + path.WriteString("/") + path.WriteString(r.ActionGroup) + } + + return opensearch.BuildRequest( + "GET", + path.String(), + nil, + make(map[string]string), + r.Header, + ) +} + +// ActionGroupsGetResp represents the returned struct of the actiongroups get response +type ActionGroupsGetResp struct { + Groups map[string]ActionGroupsGet + response *opensearch.Response +} + +// Inspect returns the Inspect type containing the raw *opensearch.Reponse +func (r ActionGroupsGetResp) Inspect() Inspect { + return Inspect{Response: r.response} +} + +// ActionGroupsGet is a sub type of ActionGroupsGetResp represeting information about an action group +type ActionGroupsGet struct { + Reserved bool `json:"reserved"` + Hidden bool `json:"hidden"` + AllowedActions []string `json:"allowed_actions"` + Static bool `json:"static"` + Description string `json:"description,omitempty"` + Type string `json:"type,omitempty"` +} diff --git a/plugins/security/api_actiongroups-patch.go b/plugins/security/api_actiongroups-patch.go new file mode 100644 index 000000000..225558e6e --- /dev/null +++ b/plugins/security/api_actiongroups-patch.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. + +package security + +import ( + "bytes" + "encoding/json" + "net/http" + "strings" + + "github.com/opensearch-project/opensearch-go/v3" +) + +// ActionGroupsPatchReq represents possible options for the actiongroups patch request +type ActionGroupsPatchReq struct { + ActionGroup string + Body ActionGroupsPatchBody + + Header http.Header +} + +// GetRequest returns the *http.Request that gets executed by the client +func (r ActionGroupsPatchReq) GetRequest() (*http.Request, error) { + body, err := json.Marshal(r.Body) + if err != nil { + return nil, err + } + + var path strings.Builder + path.Grow(len("/_plugins/_security/api/actiongroups/") + len(r.ActionGroup)) + path.WriteString("/_plugins/_security/api/actiongroups") + if len(r.ActionGroup) > 0 { + path.WriteString("/") + path.WriteString(r.ActionGroup) + } + + return opensearch.BuildRequest( + "PATCH", + path.String(), + bytes.NewReader(body), + make(map[string]string), + r.Header, + ) +} + +// ActionGroupsPatchResp represents the returned struct of the actiongroups patch response +type ActionGroupsPatchResp struct { + Status string `json:"status"` + Message string `json:"message"` + response *opensearch.Response +} + +// Inspect returns the Inspect type containing the raw *opensearch.Reponse +func (r ActionGroupsPatchResp) Inspect() Inspect { + return Inspect{Response: r.response} +} + +// ActionGroupsPatchBody represents the request body for the action groups patch request +type ActionGroupsPatchBody []ActionGroupsPatchBodyItem + +// ActionGroupsPatchBodyItem is a sub type of ActionGroupsPatchBody represeting an action group +type ActionGroupsPatchBodyItem struct { + OP string `json:"op"` + Path string `json:"path"` + Value any `json:"value,omitempty"` +} diff --git a/plugins/security/api_actiongroups-put.go b/plugins/security/api_actiongroups-put.go new file mode 100644 index 000000000..9ff52cbfc --- /dev/null +++ b/plugins/security/api_actiongroups-put.go @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. + +package security + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + "github.com/opensearch-project/opensearch-go/v3" +) + +// ActionGroupsPutReq represents possible options for the actiongroups put request +type ActionGroupsPutReq struct { + ActionGroup string + Body ActionGroupsPutBody + + Header http.Header +} + +// GetRequest returns the *http.Request that gets executed by the client +func (r ActionGroupsPutReq) GetRequest() (*http.Request, error) { + body, err := json.Marshal(r.Body) + if err != nil { + return nil, err + } + + return opensearch.BuildRequest( + "PUT", + fmt.Sprintf("/_plugins/_security/api/actiongroups/%s", r.ActionGroup), + bytes.NewReader(body), + make(map[string]string), + r.Header, + ) +} + +// ActionGroupsPutResp represents the returned struct of the actiongroups put response +type ActionGroupsPutResp struct { + Status string `json:"status"` + Message string `json:"message"` + response *opensearch.Response +} + +// Inspect returns the Inspect type containing the raw *opensearch.Reponse +func (r ActionGroupsPutResp) Inspect() Inspect { + return Inspect{Response: r.response} +} + +// ActionGroupsPutBody represents the request body for the action groups put request +type ActionGroupsPutBody struct { + AllowedActions []string `json:"allowed_actions"` + Type *string `json:"type,omitempty"` + Description *string `json:"description,omitempty"` +} diff --git a/plugins/security/api_actiongroups.go b/plugins/security/api_actiongroups.go new file mode 100644 index 000000000..a5c5755a6 --- /dev/null +++ b/plugins/security/api_actiongroups.go @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. + +package security + +import ( + "context" +) + +type actiongroupsClient struct { + apiClient *Client +} + +// Get executes a get actiongroups request with the optional ActionGroupsGetReq +func (c actiongroupsClient) Get(ctx context.Context, req *ActionGroupsGetReq) (ActionGroupsGetResp, error) { + if req == nil { + req = &ActionGroupsGetReq{} + } + + var ( + data ActionGroupsGetResp + err error + ) + if data.response, err = c.apiClient.do(ctx, req, &data); err != nil { + return data, err + } + + return data, nil +} + +// Put executes a put actiongroups request with the required ActionGroupsPutReq +func (c actiongroupsClient) Put(ctx context.Context, req ActionGroupsPutReq) (ActionGroupsPutResp, error) { + var ( + data ActionGroupsPutResp + err error + ) + if data.response, err = c.apiClient.do(ctx, req, &data); err != nil { + return data, err + } + + return data, nil +} + +// Delete executes a delete actiongroups request with the required ActionGroupsDeleteReq +func (c actiongroupsClient) Delete(ctx context.Context, req ActionGroupsDeleteReq) (ActionGroupsDeleteResp, error) { + var ( + data ActionGroupsDeleteResp + err error + ) + if data.response, err = c.apiClient.do(ctx, req, &data); err != nil { + return data, err + } + + return data, nil +} + +// Patch executes a patch actiongroups request with the required ActionGroupsPatchReq +func (c actiongroupsClient) Patch(ctx context.Context, req ActionGroupsPatchReq) (ActionGroupsPatchResp, error) { + var ( + data ActionGroupsPatchResp + err error + ) + if data.response, err = c.apiClient.do(ctx, req, &data); err != nil { + return data, err + } + + return data, nil +} diff --git a/plugins/security/api_actiongroups_test.go b/plugins/security/api_actiongroups_test.go new file mode 100644 index 000000000..ac6a5a8ac --- /dev/null +++ b/plugins/security/api_actiongroups_test.go @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// The OpenSearch Contributors require contributions made to +// this file be licensed under the Apache-2.0 license or a +// compatible open source license. +// +//go:build integration + +package security_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/opensearch-project/opensearch-go/v3" + ostest "github.com/opensearch-project/opensearch-go/v3/internal/test" + "github.com/opensearch-project/opensearch-go/v3/plugins/security" + ossectest "github.com/opensearch-project/opensearch-go/v3/plugins/security/internal/test" +) + +func TestActiongroupsClient(t *testing.T) { + ostest.SkipIfNotSecure(t) + client, err := ossectest.NewClient() + require.Nil(t, err) + + failingClient, err := ossectest.CreateFailingClient() + require.Nil(t, err) + + type actiongroupsTests struct { + Name string + Results func() (ossectest.Response, error) + } + + testCases := []struct { + Name string + Tests []actiongroupsTests + }{ + { + Name: "Get", + Tests: []actiongroupsTests{ + { + Name: "without request", + Results: func() (ossectest.Response, error) { + return client.ActionGroups.Get(nil, nil) + }, + }, + { + Name: "with request", + Results: func() (ossectest.Response, error) { + return client.ActionGroups.Get(nil, &security.ActionGroupsGetReq{ActionGroup: "write"}) + }, + }, + { + Name: "inspect", + Results: func() (ossectest.Response, error) { + return failingClient.ActionGroups.Get(nil, nil) + }, + }, + }, + }, + { + Name: "Put", + Tests: []actiongroupsTests{ + { + Name: "with request", + Results: func() (ossectest.Response, error) { + return client.ActionGroups.Put( + nil, + security.ActionGroupsPutReq{ + ActionGroup: "test", + Body: security.ActionGroupsPutBody{ + AllowedActions: []string{"indices:data/read/msearch*", "indices:admin/mapping/put"}, + Type: opensearch.ToPointer("index"), + Description: opensearch.ToPointer("Test"), + }, + }, + ) + }, + }, + { + Name: "inspect", + Results: func() (ossectest.Response, error) { + return failingClient.ActionGroups.Put(nil, security.ActionGroupsPutReq{}) + }, + }, + }, + }, + { + Name: "Delete", + Tests: []actiongroupsTests{ + { + Name: "with request", + Results: func() (ossectest.Response, error) { + return client.ActionGroups.Delete(nil, security.ActionGroupsDeleteReq{ActionGroup: "test"}) + }, + }, + { + Name: "inspect", + Results: func() (ossectest.Response, error) { + return failingClient.ActionGroups.Delete(nil, security.ActionGroupsDeleteReq{}) + }, + }, + }, + }, + { + Name: "Patch", + Tests: []actiongroupsTests{ + { + Name: "with request", + Results: func() (ossectest.Response, error) { + return client.ActionGroups.Patch( + nil, + security.ActionGroupsPatchReq{ + Body: security.ActionGroupsPatchBody{security.ActionGroupsPatchBodyItem{ + OP: "add", + Path: "/test", + Value: security.ActionGroupsPutBody{ + AllowedActions: []string{"indices:data/read/msearch*", "indices:admin/mapping/put"}, + }, + }, + }, + }, + ) + }, + }, + { + Name: "inspect", + Results: func() (ossectest.Response, error) { + return failingClient.ActionGroups.Patch(nil, security.ActionGroupsPatchReq{}) + }, + }, + }, + }, + } + for _, value := range testCases { + t.Run(value.Name, func(t *testing.T) { + for _, testCase := range value.Tests { + t.Run(testCase.Name, func(t *testing.T) { + res, err := testCase.Results() + if testCase.Name == "inspect" { + assert.NotNil(t, err) + assert.NotNil(t, res) + ossectest.VerifyInspect(t, res.Inspect()) + } else { + require.Nil(t, err) + require.NotNil(t, res) + assert.NotNil(t, res.Inspect().Response) + if value.Name != "Get" { + ostest.CompareRawJSONwithParsedJSON(t, res, res.Inspect().Response) + } + } + }) + } + }) + } + t.Run("ValidateResponse", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { + resp, err := client.ActionGroups.Get(nil, nil) + assert.Nil(t, err) + assert.NotNil(t, resp) + ostest.CompareRawJSONwithParsedJSON(t, resp.Groups, resp.Inspect().Response) + }) + }) +}