diff --git a/models/add_policy_request.go b/models/add_policy_request.go index e6039c413..3eebb1000 100644 --- a/models/add_policy_request.go +++ b/models/add_policy_request.go @@ -34,12 +34,13 @@ import ( // swagger:model addPolicyRequest type AddPolicyRequest struct { - // definition - Definition string `json:"definition,omitempty"` - // name // Required: true Name *string `json:"name"` + + // policy + // Required: true + Policy *string `json:"policy"` } // Validate validates this add policy request @@ -50,6 +51,10 @@ func (m *AddPolicyRequest) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validatePolicy(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -65,6 +70,15 @@ func (m *AddPolicyRequest) validateName(formats strfmt.Registry) error { return nil } +func (m *AddPolicyRequest) validatePolicy(formats strfmt.Registry) error { + + if err := validate.Required("policy", "body", m.Policy); err != nil { + return err + } + + return nil +} + // MarshalBinary interface implementation func (m *AddPolicyRequest) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/models/policy.go b/models/policy.go index a1f263bfd..32c61329c 100644 --- a/models/policy.go +++ b/models/policy.go @@ -23,9 +23,6 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( - "strconv" - - "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" ) @@ -38,49 +35,12 @@ type Policy struct { // name Name string `json:"name,omitempty"` - // statements - Statements []*Statement `json:"statements"` - - // version - Version string `json:"version,omitempty"` + // policy + Policy string `json:"policy,omitempty"` } // Validate validates this policy func (m *Policy) Validate(formats strfmt.Registry) error { - var res []error - - if err := m.validateStatements(formats); err != nil { - res = append(res, err) - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} - -func (m *Policy) validateStatements(formats strfmt.Registry) error { - - if swag.IsZero(m.Statements) { // not required - return nil - } - - for i := 0; i < len(m.Statements); i++ { - if swag.IsZero(m.Statements[i]) { // not required - continue - } - - if m.Statements[i] != nil { - if err := m.Statements[i].Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("statements" + "." + strconv.Itoa(i)) - } - return err - } - } - - } - return nil } diff --git a/portal-ui/src/screens/Console/Policies/AddPolicy.tsx b/portal-ui/src/screens/Console/Policies/AddPolicy.tsx index c5c0f3495..e1132fd11 100644 --- a/portal-ui/src/screens/Console/Policies/AddPolicy.tsx +++ b/portal-ui/src/screens/Console/Policies/AddPolicy.tsx @@ -81,7 +81,7 @@ class AddPolicy extends React.Component { api .invoke("POST", "/api/v1/policies", { name: policyName, - definition: policyDefinition + policy: policyDefinition }) .then(res => { this.setState( @@ -143,6 +143,7 @@ class AddPolicy extends React.Component { )} { { diff --git a/portal-ui/src/screens/Console/Policies/PolicyBuilder.tsx b/portal-ui/src/screens/Console/Policies/PolicyBuilder.tsx deleted file mode 100644 index 28cf2c076..000000000 --- a/portal-ui/src/screens/Console/Policies/PolicyBuilder.tsx +++ /dev/null @@ -1,209 +0,0 @@ -// This file is part of MinIO Kubernetes Cloud -// Copyright (c) 2020 MinIO, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import React from "react"; -import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import Grid from "@material-ui/core/Grid"; -import remove from "lodash/remove"; -import { - Checkbox, - FormControlLabel, - FormGroup, - FormLabel, - Paper, - Radio, - RadioGroup -} from "@material-ui/core"; -import { Statement } from "./types"; - -const styles = (theme: Theme) => - createStyles({ - root: { - flexGrow: 1 - }, - errorBlock: { - color: "red" - }, - jsonPolicyEditor: { - minHeight: 400, - width: "100%" - }, - codeMirror: { - fontSize: 14 - }, - paper: { - padding: theme.spacing(1), - textAlign: "center", - color: theme.palette.text.secondary - } - }); - -interface IPolicyBuilderProps { - classes: any; - policyDefinition: string; -} - -interface IPolicyBuilderState { - policyString: string; - currentStatement: Statement; - statements: Statement[]; - currentStatementWrite: boolean; - currentStatementRead: boolean; -} - -class PolicyBuilder extends React.Component< - IPolicyBuilderProps, - IPolicyBuilderState -> { - state: IPolicyBuilderState = { - policyString: "", - statements: [], - currentStatement: { - effect: "", - actions: [], - resources: [] - }, - currentStatementWrite: false, - currentStatementRead: false - }; - - render() { - const { classes, policyDefinition } = this.props; - const { - currentStatement, - currentStatementWrite, - currentStatementRead - } = this.state; - console.log(currentStatement); - return ( -
- - - - - - Effect - , - value: string - ) => { - this.setState({ - currentStatement: { ...currentStatement, effect: value } - }); - }} - > - } - label="Deny" - /> - } - label="Allow" - /> - - - - - - Actions - - , - checked: boolean - ) => { - const readActions = [ - "s3:ListBucket", - "s3:GetObject", - "s3:GetBucketLocation" - ]; - let actions = currentStatement.actions; - if (checked) { - actions.push(...readActions); - } else { - actions = remove(actions, action => - readActions.includes(action) - ); - } - this.setState({ - currentStatement: { - ...currentStatement, - actions: actions - } - }); - this.setState({ currentStatementRead: checked }); - }} - name="read" - /> - } - label="Read Only" - /> - , - checked: boolean - ) => { - const writeActions = ["s3:PutObject"]; - let actions = currentStatement.actions; - if (checked) { - actions.push(...writeActions); - } else { - actions = remove(actions, action => - writeActions.includes(action) - ); - } - this.setState({ - currentStatement: { - ...currentStatement, - actions: actions - } - }); - this.setState({ currentStatementWrite: checked }); - }} - name="write" - /> - } - label="Write Only" - /> - - - - - - Resources - - - - - -
- ); - } -} - -export default withStyles(styles)(PolicyBuilder); diff --git a/portal-ui/src/screens/Console/Policies/types.ts b/portal-ui/src/screens/Console/Policies/types.ts index df0b73f2f..bf4b632f2 100644 --- a/portal-ui/src/screens/Console/Policies/types.ts +++ b/portal-ui/src/screens/Console/Policies/types.ts @@ -14,16 +14,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -export interface Statement { - effect: string; - actions: string[]; - resources: string[]; -} - export interface Policy { name: string; - version: string; - statements: Statement[]; + policy: string; } export interface PolicyList { diff --git a/restapi/admin_policies.go b/restapi/admin_policies.go index ff30d66cc..fd54cd2e5 100644 --- a/restapi/admin_policies.go +++ b/restapi/admin_policies.go @@ -18,7 +18,6 @@ package restapi import ( "context" - "encoding/json" "log" "github.com/go-openapi/errors" @@ -74,39 +73,6 @@ func registersPoliciesHandler(api *operations.McsAPI) { }) } -type rawStatement struct { - Action []string `json:"Action"` - Effect string `json:"Effect"` - Resource []string `json:"Resource"` -} - -type rawPolicy struct { - Name string `json:"Name"` - Statement []*rawStatement `json:"Statement"` - Version string `json:"Version"` -} - -// parseRawPolicy() converts from *rawPolicy to *models.Policy -// Iterates over the raw statements and copied them to models.policy -// this is need it until fixed from minio/minio side: https://github.com/minio/minio/issues/9171 -func parseRawPolicy(rawPolicy *rawPolicy) *models.Policy { - var statements []*models.Statement - for _, rawStatement := range rawPolicy.Statement { - statement := &models.Statement{ - Actions: rawStatement.Action, - Effect: rawStatement.Effect, - Resources: rawStatement.Resource, - } - statements = append(statements, statement) - } - policy := &models.Policy{ - Name: rawPolicy.Name, - Version: rawPolicy.Version, - Statements: statements, - } - return policy -} - // listPolicies calls MinIO server to list all policy names present on the server. // listPolicies() converts the map[string][]byte returned by client.listPolicies() // to []*models.Policy by iterating over each key in policyRawMap and @@ -118,13 +84,10 @@ func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, err return nil, err } for name, policyRaw := range policyRawMap { - var rawPolicy *rawPolicy - if err := json.Unmarshal(policyRaw, &rawPolicy); err != nil { - return nil, err - } - policy := parseRawPolicy(rawPolicy) - policy.Name = name - policies = append(policies, policy) + policies = append(policies, &models.Policy{ + Name: name, + Policy: string(policyRaw), + }) } return policies, nil } @@ -217,7 +180,7 @@ func getAddPolicyResponse(params *models.AddPolicyRequest) (*models.Policy, erro // create a MinIO Admin Client interface implementation // defining the client to be used adminClient := adminClient{client: mAdmin} - policy, err := addPolicy(ctx, adminClient, *params.Name, params.Definition) + policy, err := addPolicy(ctx, adminClient, *params.Name, *params.Policy) if err != nil { log.Println("error adding policy") return nil, err @@ -226,21 +189,19 @@ func getAddPolicyResponse(params *models.AddPolicyRequest) (*models.Policy, erro } // policyInfo calls MinIO server to retrieve information of a canned policy. -// policyInfo() takes a policy name, obtains an []byte (represents a string in JSON format) -// from the MinIO server and then convert it to *models.Policy , in the future this will change +// policyInfo() takes a policy name, obtains the []byte (represents a string in JSON format) +// and return it as *models.Policy , in the future this will change // to a Policy struct{} - https://github.com/minio/minio/issues/9171 func policyInfo(ctx context.Context, client MinioAdmin, name string) (*models.Policy, error) { policyRaw, err := client.getPolicy(ctx, name) if err != nil { return nil, err } - var rawPolicy *rawPolicy - if err := json.Unmarshal(policyRaw, &rawPolicy); err != nil { - return nil, err + policy := &models.Policy{ + Name: name, + Policy: string(policyRaw), } - policyObject := parseRawPolicy(rawPolicy) - policyObject.Name = name - return policyObject, nil + return policy, nil } // getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output diff --git a/restapi/admin_policies_test.go b/restapi/admin_policies_test.go index cda87b2a4..f1f43c1ca 100644 --- a/restapi/admin_policies_test.go +++ b/restapi/admin_policies_test.go @@ -70,45 +70,16 @@ func TestListPolicies(t *testing.T) { } assertPoliciesMap := map[string]models.Policy{ "readonly": { - Name: "readonly", - Statements: []*models.Statement{ - { - Actions: []string{"s3:GetBucketLocation", "s3:GetObject"}, - Effect: "Allow", - Resources: []string{"arn:aws:s3:::*"}, - }, - }, - Version: "2012-10-17", + Name: "readonly", + Policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}", }, "readwrite": { - Name: "readwrite", - Statements: []*models.Statement{ - { - Actions: []string{"s3:*"}, - Effect: "Allow", - Resources: []string{"arn:aws:s3:::*"}, - }, - }, - Version: "2012-10-17", + Name: "readwrite", + Policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:*\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}", }, "diagnostics": { - Name: "diagnostics", - Statements: []*models.Statement{ - { - Actions: []string{ - "admin:ServerInfo", - "admin:HardwareInfo", - "admin:TopLocksInfo", - "admin:PerfInfo", - "admin:Profiling", - "admin:ServerTrace", - "admin:ConsoleLog", - }, - Effect: "Allow", - Resources: []string{"arn:aws:s3:::*"}, - }, - }, - Version: "2012-10-17", + Name: "diagnostics", + Policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"admin:ServerInfo\",\"admin:HardwareInfo\",\"admin:TopLocksInfo\",\"admin:PerfInfo\",\"admin:Profiling\",\"admin:ServerTrace\",\"admin:ConsoleLog\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}", }, } // mock function response from listPolicies() @@ -128,21 +99,10 @@ func TestListPolicies(t *testing.T) { // as part of each Policy for _, policy := range policiesList { assertPolicy := assertPoliciesMap[policy.Name] - // Check if policy statement has the same length as in the assertPoliciesMap - assert.Equal(len(policy.Statements), len(assertPolicy.Statements)) // Check if policy name is the same as in the assertPoliciesMap assert.Equal(policy.Name, assertPolicy.Name) - // Check if policy version is the same as in the assertPoliciesMap - assert.Equal(policy.Version, assertPolicy.Version) - // Iterate over each policy statement - for i, statement := range policy.Statements { - // Check if each statement effect is the same as in the assertPoliciesMap statement - assert.Equal(statement.Effect, assertPolicy.Statements[i].Effect) - // Check if each statement action is the same as in the assertPoliciesMap statement - assert.Equal(statement.Actions, assertPolicy.Statements[i].Actions) - // Check if each statement resource is the same as in the assertPoliciesMap resource - assert.Equal(statement.Resources, assertPolicy.Statements[i].Resources) - } + // Check if policy definition is the same as in the assertPoliciesMap + assert.Equal(policy.Policy, assertPolicy.Policy) } // Test-3 : listPolicies() Return error and see that the error is handled correctly and returned minioListPoliciesMock = func() (map[string][]byte, error) { @@ -152,17 +112,6 @@ func TestListPolicies(t *testing.T) { if assert.Error(err) { assert.Equal("error", err.Error()) } - //Test-4 : listPolicies() handles malformed json - minioListPoliciesMock = func() (map[string][]byte, error) { - malformedData := map[string][]byte{ - "malformed-policy": []byte("asdasdasdasdasd"), - } - return malformedData, nil - } - _, err = listPolicies(ctx, adminClient) - if assert.Error(err) { - assert.NotEmpty(err.Error()) - } } func TestRemovePolicy(t *testing.T) { @@ -201,15 +150,8 @@ func TestAddPolicy(t *testing.T) { return []byte(policyDefinition), nil } assertPolicy := models.Policy{ - Name: "new-policy", - Statements: []*models.Statement{ - { - Actions: []string{"s3:GetBucketLocation", "s3:GetObject", "s3:ListAllMyBuckets"}, - Effect: "Allow", - Resources: []string{"arn:aws:s3:::*"}, - }, - }, - Version: "2012-10-17", + Name: "new-policy", + Policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}", } // Test-1 : addPolicy() adds a new policy function := "addPolicy()" @@ -218,8 +160,7 @@ func TestAddPolicy(t *testing.T) { t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) } assert.Equal(policy.Name, assertPolicy.Name) - assert.Equal(policy.Version, assertPolicy.Version) - assert.Equal(len(policy.Statements), len(assertPolicy.Statements)) + assert.Equal(policy.Policy, assertPolicy.Policy) // Test-2 : addPolicy() got an error while adding policy minioAddPolicyMock = func(name, policy string) error { return errors.New("error") @@ -237,13 +178,6 @@ func TestAddPolicy(t *testing.T) { if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); assert.Error(err) { assert.Equal("error", err.Error()) } - // Test-4 : addPolicy() got an error while parsing policy - minioGetPolicyMock = func(name string) (bytes []byte, err error) { - return []byte("eaeaeaeae"), nil - } - if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); assert.Error(err) { - assert.NotEmpty(err.Error()) - } } func TestSetPolicy(t *testing.T) { diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 603821c22..487686811 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -1039,13 +1039,14 @@ func init() { "addPolicyRequest": { "type": "object", "required": [ - "name" + "name", + "policy" ], "properties": { - "definition": { + "name": { "type": "string" }, - "name": { + "policy": { "type": "string" } } @@ -1393,13 +1394,7 @@ func init() { "name": { "type": "string" }, - "statements": { - "type": "array", - "items": { - "$ref": "#/definitions/statement" - } - }, - "version": { + "policy": { "type": "string" } } @@ -1524,26 +1519,6 @@ func init() { } } }, - "statement": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "type": "string" - } - }, - "effect": { - "type": "string" - }, - "resources": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, "updateGroupRequest": { "type": "object", "required": [ @@ -2602,13 +2577,14 @@ func init() { "addPolicyRequest": { "type": "object", "required": [ - "name" + "name", + "policy" ], "properties": { - "definition": { + "name": { "type": "string" }, - "name": { + "policy": { "type": "string" } } @@ -2956,13 +2932,7 @@ func init() { "name": { "type": "string" }, - "statements": { - "type": "array", - "items": { - "$ref": "#/definitions/statement" - } - }, - "version": { + "policy": { "type": "string" } } @@ -3087,26 +3057,6 @@ func init() { } } }, - "statement": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "type": "string" - } - }, - "effect": { - "type": "string" - }, - "resources": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, "updateGroupRequest": { "type": "object", "required": [ diff --git a/swagger.yml b/swagger.yml index 0b3f61de7..d6a1ce0e7 100644 --- a/swagger.yml +++ b/swagger.yml @@ -780,30 +780,13 @@ definitions: type: integer format: int64 title: total number of groups - statement: - type: object - properties: - effect: - type: string - actions: - type: array - items: - type: string - resources: - type: array - items: - type: string policy: type: object properties: name: type: string - version: + policy: type: string - statements: - type: array - items: - $ref: "#/definitions/statement" policyEntity: type: string enum: @@ -824,10 +807,11 @@ definitions: type: object required: - name + - policy properties: name: type: string - definition: + policy: type: string listPoliciesResponse: type: object