Re-implement policy handling in react (#1234)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
This commit is contained in:
@@ -458,7 +458,7 @@ func listExternalBucketsResponse(params user_api.ListExternalBucketsParams) (*mo
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
remoteClient := AdminClient{Client: remoteAdmin}
|
||||
buckets, err := getAccountBuckets(ctx, remoteClient, *params.Body.AccessKey)
|
||||
buckets, err := getAccountBuckets(ctx, remoteClient)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
|
||||
@@ -3661,12 +3661,6 @@ func init() {
|
||||
"access": {
|
||||
"$ref": "#/definitions/bucketAccess"
|
||||
},
|
||||
"allowedActions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"creation_date": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3709,9 +3703,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"manage": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
@@ -5204,9 +5195,14 @@ func init() {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"permissions": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/iamPolicy"
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
@@ -9482,12 +9478,6 @@ func init() {
|
||||
"access": {
|
||||
"$ref": "#/definitions/bucketAccess"
|
||||
},
|
||||
"allowedActions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"creation_date": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -9530,9 +9520,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"manage": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
@@ -11025,9 +11012,14 @@ func init() {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"policy": {
|
||||
"permissions": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/iamPolicy"
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
|
||||
@@ -24,10 +24,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/pkg/bucket/policy/condition"
|
||||
|
||||
"github.com/minio/console/pkg/acl"
|
||||
|
||||
"github.com/minio/mc/cmd"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
"github.com/minio/minio-go/v7"
|
||||
@@ -290,25 +286,13 @@ func getBucketVersionedResponse(session *models.Principal, bucketName string) (*
|
||||
}
|
||||
|
||||
// getAccountBuckets fetches a list of all buckets allowed to that particular client from MinIO Servers
|
||||
func getAccountBuckets(ctx context.Context, client MinioAdmin, accessKey string) ([]*models.Bucket, error) {
|
||||
func getAccountBuckets(ctx context.Context, client MinioAdmin) ([]*models.Bucket, error) {
|
||||
info, err := client.AccountInfo(ctx)
|
||||
if err != nil {
|
||||
return []*models.Bucket{}, err
|
||||
}
|
||||
policyInfo, err := getAccountPolicy(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var bucketInfos []*models.Bucket
|
||||
for _, bucket := range info.Buckets {
|
||||
var bucketAdminRole bool
|
||||
conditionValues := map[string][]string{
|
||||
condition.AWSUsername.Name(): {accessKey},
|
||||
}
|
||||
bucketActions := policyInfo.IsAllowedActions(bucket.Name, "", conditionValues)
|
||||
bucketAdminRoleActions := bucketActions.Intersection(acl.BucketAdminRole)
|
||||
bucketAdminRole = len(bucketAdminRoleActions) > 0
|
||||
|
||||
bucketElem := &models.Bucket{
|
||||
CreationDate: bucket.Created.Format(time.RFC3339),
|
||||
Details: &models.BucketDetails{
|
||||
@@ -321,7 +305,6 @@ func getAccountBuckets(ctx context.Context, client MinioAdmin, accessKey string)
|
||||
Name: swag.String(bucket.Name),
|
||||
Objects: int64(bucket.Objects),
|
||||
Size: int64(bucket.Size),
|
||||
Manage: bucketAdminRole,
|
||||
}
|
||||
|
||||
if bucket.Details != nil {
|
||||
@@ -358,7 +341,7 @@ func getListBucketsResponse(session *models.Principal) (*models.ListBucketsRespo
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
adminClient := AdminClient{Client: mAdmin}
|
||||
buckets, err := getAccountBuckets(ctx, adminClient, session.AccountAccessKey)
|
||||
buckets, err := getAccountBuckets(ctx, adminClient)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
@@ -493,21 +476,12 @@ func getBucketSetPolicyResponse(session *models.Principal, bucketName string, re
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
minioClient := minioClient{client: mClient}
|
||||
|
||||
mAdmin, err := NewMinioAdminClient(session)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
adminClient := AdminClient{Client: mAdmin}
|
||||
|
||||
// set bucket access policy
|
||||
if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access); err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
// get updated bucket details and return it
|
||||
bucket, err := getBucketInfo(ctx, minioClient, adminClient, bucketName, session.AccountAccessKey)
|
||||
bucket, err := getBucketInfo(ctx, minioClient, bucketName)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
@@ -566,29 +540,7 @@ func getDeleteBucketResponse(session *models.Principal, params user_api.DeleteBu
|
||||
}
|
||||
|
||||
// getBucketInfo return bucket information including name, policy access, size and creation date
|
||||
func getBucketInfo(ctx context.Context, client MinioClient, adminClient MinioAdmin, bucketName string, accountName string) (*models.Bucket, error) {
|
||||
// Get Account Policy
|
||||
policyInfo, err := getAccountPolicy(ctx, adminClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var bucketAdminRole bool
|
||||
// Retrieve list of allowed bucketActionsArray on the bucket
|
||||
// TODO: Add all the possible variables
|
||||
conditionValues := map[string][]string{
|
||||
condition.AWSUsername.Name(): {accountName},
|
||||
}
|
||||
|
||||
bucketActions := policyInfo.IsAllowedActions(bucketName, "", conditionValues)
|
||||
// Check if one of these bucketActionsArray belongs to administrative bucketActionsArray
|
||||
bucketAdminRoleActions := bucketActions.Intersection(acl.BucketAdminRole)
|
||||
bucketAdminRole = len(bucketAdminRoleActions) > 0
|
||||
var bucketActionsArray []string
|
||||
for _, action := range bucketActions.ToSlice() {
|
||||
bucketActionsArray = append(bucketActionsArray, string(action))
|
||||
}
|
||||
|
||||
func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (*models.Bucket, error) {
|
||||
var bucketAccess models.BucketAccess
|
||||
policyStr, err := client.getBucketPolicy(context.Background(), bucketName)
|
||||
if err != nil {
|
||||
@@ -611,29 +563,21 @@ func getBucketInfo(ctx context.Context, client MinioClient, adminClient MinioAdm
|
||||
bucketAccess = models.BucketAccessCUSTOM
|
||||
}
|
||||
bucketTags, err := client.GetBucketTagging(ctx, bucketName)
|
||||
var bucket *models.Bucket
|
||||
if err == nil && bucketTags != nil {
|
||||
bucket = &models.Bucket{
|
||||
Name: &bucketName,
|
||||
Access: &bucketAccess,
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
AllowedActions: bucketActionsArray,
|
||||
Manage: bucketAdminRole,
|
||||
Details: &models.BucketDetails{Tags: bucketTags.ToMap()},
|
||||
}
|
||||
} else {
|
||||
bucket = &models.Bucket{
|
||||
Name: &bucketName,
|
||||
Access: &bucketAccess,
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
AllowedActions: bucketActionsArray,
|
||||
Manage: bucketAdminRole,
|
||||
Details: &models.BucketDetails{},
|
||||
}
|
||||
if err != nil {
|
||||
// we can tolerate this error
|
||||
LogError("error getting bucket tags: %v", err)
|
||||
}
|
||||
return bucket, nil
|
||||
bucketDetails := &models.BucketDetails{}
|
||||
if bucketTags != nil {
|
||||
bucketDetails.Tags = bucketTags.ToMap()
|
||||
}
|
||||
return &models.Bucket{
|
||||
Name: &bucketName,
|
||||
Access: &bucketAccess,
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
Details: bucketDetails,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getBucketInfoResponse calls getBucketInfo() to get the bucket's info
|
||||
@@ -647,16 +591,7 @@ func getBucketInfoResponse(session *models.Principal, params user_api.BucketInfo
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
minioClient := minioClient{client: mClient}
|
||||
|
||||
mAdmin, err := NewMinioAdminClient(session)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
adminClient := AdminClient{Client: mAdmin}
|
||||
|
||||
bucket, err := getBucketInfo(ctx, minioClient, adminClient, params.Name, session.AccountAccessKey)
|
||||
bucket, err := getBucketInfo(ctx, minioClient, params.Name)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func TestListBucket(t *testing.T) {
|
||||
// get list buckets response this response should have Name, CreationDate, Size and Access
|
||||
// as part of of each bucket
|
||||
function := "getaAcountUsageInfo()"
|
||||
bucketList, err := getAccountBuckets(ctx, adminClient, "")
|
||||
bucketList, err := getAccountBuckets(ctx, adminClient)
|
||||
if err != nil {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
|
||||
}
|
||||
@@ -197,7 +197,7 @@ func TestListBucket(t *testing.T) {
|
||||
minioAccountInfoMock = func(ctx context.Context) (madmin.AccountInfo, error) {
|
||||
return madmin.AccountInfo{}, errors.New("error")
|
||||
}
|
||||
_, err = getAccountBuckets(ctx, adminClient, "")
|
||||
_, err = getAccountBuckets(ctx, adminClient)
|
||||
if assert.Error(err) {
|
||||
assert.Equal("error", err.Error())
|
||||
}
|
||||
@@ -257,7 +257,6 @@ func TestBucketInfo(t *testing.T) {
|
||||
// mock minIO client
|
||||
minClient := minioClientMock{}
|
||||
ctx := context.Background()
|
||||
adminClient := adminClientMock{}
|
||||
function := "getBucketInfo()"
|
||||
|
||||
// Test-1: getBucketInfo() get a bucket with PRIVATE access
|
||||
@@ -308,7 +307,7 @@ func TestBucketInfo(t *testing.T) {
|
||||
return mockBucketList, nil
|
||||
}
|
||||
|
||||
bucketInfo, err := getBucketInfo(ctx, minClient, adminClient, bucketToSet, "user1")
|
||||
bucketInfo, err := getBucketInfo(ctx, minClient, bucketToSet)
|
||||
if err != nil {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
|
||||
}
|
||||
@@ -330,7 +329,7 @@ func TestBucketInfo(t *testing.T) {
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
}
|
||||
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet, "bucket1")
|
||||
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
|
||||
if err != nil {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
|
||||
}
|
||||
@@ -352,7 +351,7 @@ func TestBucketInfo(t *testing.T) {
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
}
|
||||
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet, "bucket1")
|
||||
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
|
||||
if err != nil {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
|
||||
}
|
||||
@@ -373,7 +372,7 @@ func TestBucketInfo(t *testing.T) {
|
||||
CreationDate: "", // to be implemented
|
||||
Size: 0, // to be implemented
|
||||
}
|
||||
_, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet, "bucket1")
|
||||
_, err = getBucketInfo(ctx, minClient, bucketToSet)
|
||||
if assert.Error(err) {
|
||||
assert.Equal("invalid character 'p' looking for beginning of value", err.Error())
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/minio/pkg/bucket/policy/condition"
|
||||
|
||||
minioIAMPolicy "github.com/minio/pkg/iam/policy"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/pkg/acl"
|
||||
@@ -91,14 +95,82 @@ func getSessionResponse(session *models.Principal) (*models.SessionResponse, *mo
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorGenericInvalidSession)
|
||||
}
|
||||
// by default every user starts with an empty array of available actions
|
||||
// by default every user starts with an empty array of available val
|
||||
// therefore we would have access only to pages that doesn't require any privilege
|
||||
// ie: service-account page
|
||||
var actions []string
|
||||
// if a policy is assigned to this user we parse the actions from there
|
||||
// if a policy is assigned to this user we parse the val from there
|
||||
if policy != nil {
|
||||
actions = acl.GetActionsStringFromPolicy(policy)
|
||||
}
|
||||
|
||||
// This actions will be global, meaning has to be attached to all resources
|
||||
conditionValues := map[string][]string{
|
||||
condition.AWSUsername.Name(): {session.AccountAccessKey},
|
||||
}
|
||||
defaultActions := policy.IsAllowedActions("", "", conditionValues)
|
||||
consoleResourceName := "console-ui"
|
||||
permissions := map[string]minioIAMPolicy.ActionSet{
|
||||
consoleResourceName: defaultActions,
|
||||
}
|
||||
deniedActions := map[string]minioIAMPolicy.ActionSet{}
|
||||
for _, statement := range policy.Statements {
|
||||
for _, resource := range statement.Resources.ToSlice() {
|
||||
resourceName := resource.String()
|
||||
statementActions := statement.Actions.ToSlice()
|
||||
if statement.Effect == "Allow" {
|
||||
// check if val are denied before adding them to the map
|
||||
var allowedActions []minioIAMPolicy.Action
|
||||
if dActions, ok := deniedActions[resourceName]; ok {
|
||||
for _, action := range statementActions {
|
||||
if len(dActions.Intersection(minioIAMPolicy.NewActionSet(action))) == 0 {
|
||||
// It's ok to allow this action
|
||||
allowedActions = append(allowedActions, action)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allowedActions = statementActions
|
||||
}
|
||||
|
||||
// Add validated actions
|
||||
if resourceActions, ok := permissions[resourceName]; ok {
|
||||
mergedActions := append(resourceActions.ToSlice(), allowedActions...)
|
||||
permissions[resourceName] = minioIAMPolicy.NewActionSet(mergedActions...)
|
||||
} else {
|
||||
mergedActions := append(defaultActions.ToSlice(), allowedActions...)
|
||||
permissions[resourceName] = minioIAMPolicy.NewActionSet(mergedActions...)
|
||||
}
|
||||
} else {
|
||||
// Add new banned actions to the map
|
||||
if resourceActions, ok := deniedActions[resourceName]; ok {
|
||||
mergedActions := append(resourceActions.ToSlice(), statementActions...)
|
||||
deniedActions[resourceName] = minioIAMPolicy.NewActionSet(mergedActions...)
|
||||
} else {
|
||||
deniedActions[resourceName] = statement.Actions
|
||||
}
|
||||
// Remove existing val from key if necessary
|
||||
if currentResourceActions, ok := permissions[resourceName]; ok {
|
||||
var newAllowedActions []minioIAMPolicy.Action
|
||||
for _, action := range currentResourceActions.ToSlice() {
|
||||
if len(deniedActions[resourceName].Intersection(minioIAMPolicy.NewActionSet(action))) == 0 {
|
||||
// It's ok to allow this action
|
||||
newAllowedActions = append(newAllowedActions, action)
|
||||
}
|
||||
}
|
||||
permissions[resourceName] = minioIAMPolicy.NewActionSet(newAllowedActions...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resourcePermissions := map[string][]string{}
|
||||
for key, val := range permissions {
|
||||
var resourceActions []string
|
||||
for _, action := range val.ToSlice() {
|
||||
resourceActions = append(resourceActions, string(action))
|
||||
}
|
||||
resourcePermissions[key] = resourceActions
|
||||
|
||||
}
|
||||
rawPolicy, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorGenericInvalidSession)
|
||||
@@ -114,7 +186,7 @@ func getSessionResponse(session *models.Principal) (*models.SessionResponse, *mo
|
||||
Status: models.SessionResponseStatusOk,
|
||||
Operator: false,
|
||||
DistributedMode: isErasureMode(),
|
||||
Policy: sessionPolicy,
|
||||
Permissions: resourcePermissions,
|
||||
}
|
||||
return sessionResp, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user