github.com/minio/console@v1.3.0/api/admin_policies.go (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"sort"
    25  	"strings"
    26  
    27  	bucketApi "github.com/minio/console/api/operations/bucket"
    28  	policyApi "github.com/minio/console/api/operations/policy"
    29  	"github.com/minio/console/pkg/utils"
    30  	s3 "github.com/minio/minio-go/v7"
    31  
    32  	"github.com/go-openapi/runtime/middleware"
    33  	"github.com/minio/console/api/operations"
    34  	"github.com/minio/console/models"
    35  	iampolicy "github.com/minio/pkg/v2/policy"
    36  
    37  	policies "github.com/minio/console/api/policy"
    38  )
    39  
    40  func registersPoliciesHandler(api *operations.ConsoleAPI) {
    41  	// List Policies
    42  	api.PolicyListPoliciesHandler = policyApi.ListPoliciesHandlerFunc(func(params policyApi.ListPoliciesParams, session *models.Principal) middleware.Responder {
    43  		listPoliciesResponse, err := getListPoliciesResponse(session, params)
    44  		if err != nil {
    45  			return policyApi.NewListPoliciesDefault(err.Code).WithPayload(err.APIError)
    46  		}
    47  		return policyApi.NewListPoliciesOK().WithPayload(listPoliciesResponse)
    48  	})
    49  	// Policy Info
    50  	api.PolicyPolicyInfoHandler = policyApi.PolicyInfoHandlerFunc(func(params policyApi.PolicyInfoParams, session *models.Principal) middleware.Responder {
    51  		policyInfo, err := getPolicyInfoResponse(session, params)
    52  		if err != nil {
    53  			return policyApi.NewPolicyInfoDefault(err.Code).WithPayload(err.APIError)
    54  		}
    55  		return policyApi.NewPolicyInfoOK().WithPayload(policyInfo)
    56  	})
    57  	// Add Policy
    58  	api.PolicyAddPolicyHandler = policyApi.AddPolicyHandlerFunc(func(params policyApi.AddPolicyParams, session *models.Principal) middleware.Responder {
    59  		policyResponse, err := getAddPolicyResponse(session, params)
    60  		if err != nil {
    61  			return policyApi.NewAddPolicyDefault(err.Code).WithPayload(err.APIError)
    62  		}
    63  		return policyApi.NewAddPolicyCreated().WithPayload(policyResponse)
    64  	})
    65  	// Remove Policy
    66  	api.PolicyRemovePolicyHandler = policyApi.RemovePolicyHandlerFunc(func(params policyApi.RemovePolicyParams, session *models.Principal) middleware.Responder {
    67  		if err := getRemovePolicyResponse(session, params); err != nil {
    68  			return policyApi.NewRemovePolicyDefault(err.Code).WithPayload(err.APIError)
    69  		}
    70  		return policyApi.NewRemovePolicyNoContent()
    71  	})
    72  	// Set Policy
    73  	api.PolicySetPolicyHandler = policyApi.SetPolicyHandlerFunc(func(params policyApi.SetPolicyParams, session *models.Principal) middleware.Responder {
    74  		if err := getSetPolicyResponse(session, params); err != nil {
    75  			return policyApi.NewSetPolicyDefault(err.Code).WithPayload(err.APIError)
    76  		}
    77  		return policyApi.NewSetPolicyNoContent()
    78  	})
    79  	// Set Policy Multiple User/Groups
    80  	api.PolicySetPolicyMultipleHandler = policyApi.SetPolicyMultipleHandlerFunc(func(params policyApi.SetPolicyMultipleParams, session *models.Principal) middleware.Responder {
    81  		if err := getSetPolicyMultipleResponse(session, params); err != nil {
    82  			return policyApi.NewSetPolicyMultipleDefault(err.Code).WithPayload(err.APIError)
    83  		}
    84  		return policyApi.NewSetPolicyMultipleNoContent()
    85  	})
    86  	api.BucketListPoliciesWithBucketHandler = bucketApi.ListPoliciesWithBucketHandlerFunc(func(params bucketApi.ListPoliciesWithBucketParams, session *models.Principal) middleware.Responder {
    87  		policyResponse, err := getListPoliciesWithBucketResponse(session, params)
    88  		if err != nil {
    89  			return bucketApi.NewListPoliciesWithBucketDefault(err.Code).WithPayload(err.APIError)
    90  		}
    91  		return bucketApi.NewListPoliciesWithBucketOK().WithPayload(policyResponse)
    92  	})
    93  	api.BucketListAccessRulesWithBucketHandler = bucketApi.ListAccessRulesWithBucketHandlerFunc(func(params bucketApi.ListAccessRulesWithBucketParams, session *models.Principal) middleware.Responder {
    94  		policyResponse, err := getListAccessRulesWithBucketResponse(session, params)
    95  		if err != nil {
    96  			return bucketApi.NewListAccessRulesWithBucketDefault(err.Code).WithPayload(err.APIError)
    97  		}
    98  		return bucketApi.NewListAccessRulesWithBucketOK().WithPayload(policyResponse)
    99  	})
   100  	api.BucketSetAccessRuleWithBucketHandler = bucketApi.SetAccessRuleWithBucketHandlerFunc(func(params bucketApi.SetAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
   101  		policyResponse, err := getSetAccessRuleWithBucketResponse(session, params)
   102  		if err != nil {
   103  			return bucketApi.NewSetAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
   104  		}
   105  		return bucketApi.NewSetAccessRuleWithBucketOK().WithPayload(policyResponse)
   106  	})
   107  	api.BucketDeleteAccessRuleWithBucketHandler = bucketApi.DeleteAccessRuleWithBucketHandlerFunc(func(params bucketApi.DeleteAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
   108  		policyResponse, err := getDeleteAccessRuleWithBucketResponse(session, params)
   109  		if err != nil {
   110  			return bucketApi.NewDeleteAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
   111  		}
   112  		return bucketApi.NewDeleteAccessRuleWithBucketOK().WithPayload(policyResponse)
   113  	})
   114  	api.PolicyListUsersForPolicyHandler = policyApi.ListUsersForPolicyHandlerFunc(func(params policyApi.ListUsersForPolicyParams, session *models.Principal) middleware.Responder {
   115  		policyUsersResponse, err := getListUsersForPolicyResponse(session, params)
   116  		if err != nil {
   117  			return policyApi.NewListUsersForPolicyDefault(err.Code).WithPayload(err.APIError)
   118  		}
   119  		return policyApi.NewListUsersForPolicyOK().WithPayload(policyUsersResponse)
   120  	})
   121  	api.PolicyListGroupsForPolicyHandler = policyApi.ListGroupsForPolicyHandlerFunc(func(params policyApi.ListGroupsForPolicyParams, session *models.Principal) middleware.Responder {
   122  		policyGroupsResponse, err := getListGroupsForPolicyResponse(session, params)
   123  		if err != nil {
   124  			return policyApi.NewListGroupsForPolicyDefault(err.Code).WithPayload(err.APIError)
   125  		}
   126  		return policyApi.NewListGroupsForPolicyOK().WithPayload(policyGroupsResponse)
   127  	})
   128  	// Gets policies for currently logged in user
   129  	api.PolicyGetUserPolicyHandler = policyApi.GetUserPolicyHandlerFunc(func(params policyApi.GetUserPolicyParams, session *models.Principal) middleware.Responder {
   130  		userPolicyResponse, err := getUserPolicyResponse(params.HTTPRequest.Context(), session)
   131  		if err != nil {
   132  			return policyApi.NewGetUserPolicyDefault(err.Code).WithPayload(err.APIError)
   133  		}
   134  		return policyApi.NewGetUserPolicyOK().WithPayload(userPolicyResponse)
   135  	})
   136  	// Gets policies for specified user
   137  	api.PolicyGetSAUserPolicyHandler = policyApi.GetSAUserPolicyHandlerFunc(func(params policyApi.GetSAUserPolicyParams, session *models.Principal) middleware.Responder {
   138  		userPolicyResponse, err := getSAUserPolicyResponse(session, params)
   139  		if err != nil {
   140  			return policyApi.NewGetSAUserPolicyDefault(err.Code).WithPayload(err.APIError)
   141  		}
   142  		return policyApi.NewGetSAUserPolicyOK().WithPayload(userPolicyResponse)
   143  	})
   144  }
   145  
   146  func getListAccessRulesWithBucketResponse(session *models.Principal, params bucketApi.ListAccessRulesWithBucketParams) (*models.ListAccessRulesResponse, *CodedAPIError) {
   147  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   148  	defer cancel()
   149  	bucket := params.Bucket
   150  	client, err := newS3BucketClient(session, bucket, "", getClientIP(params.HTTPRequest))
   151  	if err != nil {
   152  		return nil, ErrorWithContext(ctx, err)
   153  	}
   154  	accessRules, _ := client.GetAccessRules(ctx)
   155  	var accessRuleList []*models.AccessRule
   156  	for k, v := range accessRules {
   157  		accessRuleList = append(accessRuleList, &models.AccessRule{Prefix: k[len(bucket)+1 : len(k)-1], Access: v})
   158  	}
   159  	return &models.ListAccessRulesResponse{AccessRules: accessRuleList}, nil
   160  }
   161  
   162  func getSetAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.SetAccessRuleWithBucketParams) (bool, *CodedAPIError) {
   163  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   164  	defer cancel()
   165  	prefixAccess := params.Prefixaccess
   166  	client, err := newS3BucketClient(session, params.Bucket, prefixAccess.Prefix, getClientIP(params.HTTPRequest))
   167  	if err != nil {
   168  		return false, ErrorWithContext(ctx, err)
   169  	}
   170  	errorVal := client.SetAccess(ctx, prefixAccess.Access, false)
   171  	if errorVal != nil {
   172  		returnError := ErrorWithContext(ctx, errorVal.Cause)
   173  		minioError := s3.ToErrorResponse(errorVal.Cause)
   174  		if minioError.Code == "NoSuchBucket" {
   175  			returnError.Code = 404
   176  		}
   177  		return false, returnError
   178  	}
   179  	return true, nil
   180  }
   181  
   182  func getDeleteAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.DeleteAccessRuleWithBucketParams) (bool, *CodedAPIError) {
   183  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   184  	defer cancel()
   185  	bucket := params.Bucket
   186  	prefix := params.Prefix
   187  	client, err := newS3BucketClient(session, bucket, prefix.Prefix, getClientIP(params.HTTPRequest))
   188  	if err != nil {
   189  		return false, ErrorWithContext(ctx, err)
   190  	}
   191  	errorVal := client.SetAccess(ctx, "none", false)
   192  	if errorVal != nil {
   193  		return false, ErrorWithContext(ctx, errorVal.Cause)
   194  	}
   195  	return true, nil
   196  }
   197  
   198  func getListPoliciesWithBucketResponse(session *models.Principal, params bucketApi.ListPoliciesWithBucketParams) (*models.ListPoliciesResponse, *CodedAPIError) {
   199  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   200  	defer cancel()
   201  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   202  	if err != nil {
   203  		return nil, ErrorWithContext(ctx, err)
   204  	}
   205  	// create a MinIO Admin Client interface implementation
   206  	// defining the client to be used
   207  	adminClient := AdminClient{Client: mAdmin}
   208  
   209  	policies, err := listPoliciesWithBucket(ctx, params.Bucket, adminClient)
   210  	if err != nil {
   211  		return nil, ErrorWithContext(ctx, err)
   212  	}
   213  	// serialize output
   214  	listPoliciesResponse := &models.ListPoliciesResponse{
   215  		Policies: policies,
   216  		Total:    int64(len(policies)),
   217  	}
   218  	return listPoliciesResponse, nil
   219  }
   220  
   221  // listPoliciesWithBucket calls MinIO server to list all policy names present on the server that apply to a particular bucket.
   222  // listPoliciesWithBucket() converts the map[string][]byte returned by client.listPolicies()
   223  // to []*models.Policy by iterating over each key in policyRawMap and
   224  // then using Unmarshal on the raw bytes to create a *models.Policy
   225  func listPoliciesWithBucket(ctx context.Context, bucket string, client MinioAdmin) ([]*models.Policy, error) {
   226  	policyMap, err := client.listPolicies(ctx)
   227  	var policies []*models.Policy
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	for name, policy := range policyMap {
   232  		policy, err := parsePolicy(name, policy)
   233  		if err != nil {
   234  			return nil, err
   235  		}
   236  		if policyMatchesBucket(ctx, policy, bucket) {
   237  			policies = append(policies, policy)
   238  		}
   239  	}
   240  	return policies, nil
   241  }
   242  
   243  func policyMatchesBucket(ctx context.Context, policy *models.Policy, bucket string) bool {
   244  	policyData := &iampolicy.Policy{}
   245  	err := json.Unmarshal([]byte(policy.Policy), policyData)
   246  	if err != nil {
   247  		ErrorWithContext(ctx, fmt.Errorf("error parsing policy: %v", err))
   248  		return false
   249  	}
   250  	policyStatements := policyData.Statements
   251  	for i := 0; i < len(policyStatements); i++ {
   252  		resources := policyStatements[i].Resources
   253  		if resources.Match(bucket, map[string][]string{}) {
   254  			return true
   255  		}
   256  		if resources.Match(fmt.Sprintf("%s/*", bucket), map[string][]string{}) {
   257  			return true
   258  		}
   259  	}
   260  	return false
   261  }
   262  
   263  // listPolicies calls MinIO server to list all policy names present on the server.
   264  // listPolicies() converts the map[string][]byte returned by client.listPolicies()
   265  // to []*models.Policy by iterating over each key in policyRawMap and
   266  // then using Unmarshal on the raw bytes to create a *models.Policy
   267  func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, error) {
   268  	policyMap, err := client.listPolicies(ctx)
   269  	var policies []*models.Policy
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	for name, policy := range policyMap {
   274  		policy, err := parsePolicy(name, policy)
   275  		if err != nil {
   276  			return nil, err
   277  		}
   278  		policies = append(policies, policy)
   279  	}
   280  	return policies, nil
   281  }
   282  
   283  // getListPoliciesResponse performs listPolicies() and serializes it to the handler's output
   284  func getListPoliciesResponse(session *models.Principal, params policyApi.ListPoliciesParams) (*models.ListPoliciesResponse, *CodedAPIError) {
   285  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   286  	defer cancel()
   287  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   288  	if err != nil {
   289  		return nil, ErrorWithContext(ctx, err)
   290  	}
   291  	// create a MinIO Admin Client interface implementation
   292  	// defining the client to be used
   293  	adminClient := AdminClient{Client: mAdmin}
   294  
   295  	policies, err := listPolicies(ctx, adminClient)
   296  	if err != nil {
   297  		return nil, ErrorWithContext(ctx, err)
   298  	}
   299  	// serialize output
   300  	listPoliciesResponse := &models.ListPoliciesResponse{
   301  		Policies: policies,
   302  		Total:    int64(len(policies)),
   303  	}
   304  	return listPoliciesResponse, nil
   305  }
   306  
   307  // getListUsersForPoliciesResponse performs lists users affected by a given policy.
   308  func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *CodedAPIError) {
   309  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   310  	defer cancel()
   311  	policy, err := utils.DecodeBase64(params.Policy)
   312  	if err != nil {
   313  		return nil, ErrorWithContext(ctx, err)
   314  	}
   315  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   316  	if err != nil {
   317  		return nil, ErrorWithContext(ctx, err)
   318  	}
   319  	// create a minioClient interface implementation
   320  	// defining the client to be used
   321  	adminClient := AdminClient{Client: mAdmin}
   322  	policies, err := listPolicies(ctx, adminClient)
   323  	if err != nil {
   324  		return nil, ErrorWithContext(ctx, err)
   325  	}
   326  	found := false
   327  	for i := range policies {
   328  		if policies[i].Name == policy {
   329  			found = true
   330  		}
   331  	}
   332  	if !found {
   333  		return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
   334  	}
   335  	users, err := listUsers(ctx, adminClient)
   336  	if err != nil {
   337  		return nil, ErrorWithContext(ctx, err)
   338  	}
   339  
   340  	var filteredUsers []string
   341  	for _, user := range users {
   342  		for _, upolicy := range user.Policy {
   343  			if upolicy == policy {
   344  				filteredUsers = append(filteredUsers, user.AccessKey)
   345  				break
   346  			}
   347  		}
   348  	}
   349  	sort.Strings(filteredUsers)
   350  	return filteredUsers, nil
   351  }
   352  
   353  func getUserPolicyResponse(ctx context.Context, session *models.Principal) (string, *CodedAPIError) {
   354  	ctx, cancel := context.WithCancel(ctx)
   355  	defer cancel()
   356  	// serialize output
   357  	if session == nil {
   358  		return "nil", ErrorWithContext(ctx, ErrPolicyNotFound)
   359  	}
   360  	tokenClaims, _ := getClaimsFromToken(session.STSSessionToken)
   361  
   362  	// initialize admin client
   363  	mAdminClient, err := NewMinioAdminClient(ctx, &models.Principal{
   364  		STSAccessKeyID:     session.STSAccessKeyID,
   365  		STSSecretAccessKey: session.STSSecretAccessKey,
   366  		STSSessionToken:    session.STSSessionToken,
   367  	})
   368  	if err != nil {
   369  		return "nil", ErrorWithContext(ctx, err)
   370  	}
   371  	userAdminClient := AdminClient{Client: mAdminClient}
   372  	// Obtain the current policy assigned to this user
   373  	// necessary for generating the list of allowed endpoints
   374  	accountInfo, err := getAccountInfo(ctx, userAdminClient)
   375  	if err != nil {
   376  		return "nil", ErrorWithContext(ctx, err)
   377  	}
   378  	rawPolicy := policies.ReplacePolicyVariables(tokenClaims, accountInfo)
   379  	return string(rawPolicy), nil
   380  }
   381  
   382  func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUserPolicyParams) (*models.AUserPolicyResponse, *CodedAPIError) {
   383  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   384  	defer cancel()
   385  	// serialize output
   386  	if session == nil {
   387  		return nil, ErrorWithContext(ctx, ErrPolicyNotFound)
   388  	}
   389  	// initialize admin client
   390  	mAdminClient, err := NewMinioAdminClient(params.HTTPRequest.Context(), &models.Principal{
   391  		STSAccessKeyID:     session.STSAccessKeyID,
   392  		STSSecretAccessKey: session.STSSecretAccessKey,
   393  		STSSessionToken:    session.STSSessionToken,
   394  	})
   395  	if err != nil {
   396  		return nil, ErrorWithContext(ctx, err)
   397  	}
   398  	userAdminClient := AdminClient{Client: mAdminClient}
   399  
   400  	userName, err := utils.DecodeBase64(params.Name)
   401  	if err != nil {
   402  		return nil, ErrorWithContext(ctx, err)
   403  	}
   404  
   405  	user, err := getUserInfo(ctx, userAdminClient, userName)
   406  	if err != nil {
   407  		return nil, ErrorWithContext(ctx, err)
   408  	}
   409  	var userPolicies []string
   410  	if len(user.PolicyName) > 0 {
   411  		userPolicies = strings.Split(user.PolicyName, ",")
   412  	}
   413  
   414  	for _, group := range user.MemberOf {
   415  		groupDesc, err := groupInfo(ctx, userAdminClient, group)
   416  		if err != nil {
   417  			return nil, ErrorWithContext(ctx, err)
   418  		}
   419  		if groupDesc.Policy != "" {
   420  			userPolicies = append(userPolicies, strings.Split(groupDesc.Policy, ",")...)
   421  		}
   422  	}
   423  
   424  	allKeys := make(map[string]bool)
   425  	var userPolicyList []string
   426  
   427  	for _, item := range userPolicies {
   428  		if _, value := allKeys[item]; !value {
   429  			allKeys[item] = true
   430  			userPolicyList = append(userPolicyList, item)
   431  		}
   432  	}
   433  	var userStatements []iampolicy.Statement
   434  
   435  	for _, pol := range userPolicyList {
   436  		policy, err := getPolicyStatements(ctx, userAdminClient, pol)
   437  		if err != nil {
   438  			return nil, ErrorWithContext(ctx, err)
   439  		}
   440  		userStatements = append(userStatements, policy...)
   441  	}
   442  
   443  	combinedPolicy := iampolicy.Policy{
   444  		Version:    "2012-10-17",
   445  		Statements: userStatements,
   446  	}
   447  
   448  	stringPolicy, err := json.Marshal(combinedPolicy)
   449  	if err != nil {
   450  		return nil, ErrorWithContext(ctx, err)
   451  	}
   452  	parsedPolicy := string(stringPolicy)
   453  
   454  	getUserPoliciesResponse := &models.AUserPolicyResponse{
   455  		Policy: parsedPolicy,
   456  	}
   457  
   458  	return getUserPoliciesResponse, nil
   459  }
   460  
   461  func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.ListGroupsForPolicyParams) ([]string, *CodedAPIError) {
   462  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   463  	defer cancel()
   464  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   465  	if err != nil {
   466  		return nil, ErrorWithContext(ctx, err)
   467  	}
   468  	// create a minioClient interface implementation
   469  	// defining the client to be used
   470  	policy, err := utils.DecodeBase64(params.Policy)
   471  	if err != nil {
   472  		return nil, ErrorWithContext(ctx, err)
   473  	}
   474  	adminClient := AdminClient{Client: mAdmin}
   475  	policies, err := listPolicies(ctx, adminClient)
   476  	if err != nil {
   477  		return nil, ErrorWithContext(ctx, err)
   478  	}
   479  	found := false
   480  	for i := range policies {
   481  		if policies[i].Name == policy {
   482  			found = true
   483  		}
   484  	}
   485  	if !found {
   486  		return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
   487  	}
   488  
   489  	groups, err := adminClient.listGroups(ctx)
   490  	if err != nil {
   491  		return nil, ErrorWithContext(ctx, err)
   492  	}
   493  
   494  	var filteredGroups []string
   495  	for _, group := range groups {
   496  		info, err := groupInfo(ctx, adminClient, group)
   497  		if err != nil {
   498  			return nil, ErrorWithContext(ctx, err)
   499  		}
   500  		groupPolicies := strings.Split(info.Policy, ",")
   501  		for _, groupPolicy := range groupPolicies {
   502  			if groupPolicy == policy {
   503  				filteredGroups = append(filteredGroups, group)
   504  			}
   505  		}
   506  	}
   507  	sort.Strings(filteredGroups)
   508  	return filteredGroups, nil
   509  }
   510  
   511  // removePolicy() calls MinIO server to remove a policy based on name.
   512  func removePolicy(ctx context.Context, client MinioAdmin, name string) error {
   513  	err := client.removePolicy(ctx, name)
   514  	if err != nil {
   515  		return err
   516  	}
   517  	return nil
   518  }
   519  
   520  // getRemovePolicyResponse() performs removePolicy() and serializes it to the handler's output
   521  func getRemovePolicyResponse(session *models.Principal, params policyApi.RemovePolicyParams) *CodedAPIError {
   522  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   523  	defer cancel()
   524  	if params.Name == "" {
   525  		return ErrorWithContext(ctx, ErrPolicyNameNotInRequest)
   526  	}
   527  	policyName, err := utils.DecodeBase64(params.Name)
   528  	if err != nil {
   529  		return ErrorWithContext(ctx, err)
   530  	}
   531  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   532  	if err != nil {
   533  		return ErrorWithContext(ctx, err)
   534  	}
   535  	// create a MinIO Admin Client interface implementation
   536  	// defining the client to be used
   537  	adminClient := AdminClient{Client: mAdmin}
   538  
   539  	if err := removePolicy(ctx, adminClient, policyName); err != nil {
   540  		return ErrorWithContext(ctx, err)
   541  	}
   542  	return nil
   543  }
   544  
   545  // addPolicy calls MinIO server to add a canned policy.
   546  // addPolicy() takes name and policy in string format, policy
   547  // policy must be string in json format, in the future this will change
   548  // to a Policy struct{} - https://github.com/minio/minio/issues/9171
   549  func addPolicy(ctx context.Context, client MinioAdmin, name, policy string) (*models.Policy, error) {
   550  	iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy)))
   551  	if err != nil {
   552  		return nil, err
   553  	}
   554  	if err := client.addPolicy(ctx, name, iamp); err != nil {
   555  		return nil, err
   556  	}
   557  	policyObject, err := policyInfo(ctx, client, name)
   558  	if err != nil {
   559  		return nil, err
   560  	}
   561  	return policyObject, nil
   562  }
   563  
   564  // getAddPolicyResponse performs addPolicy() and serializes it to the handler's output
   565  func getAddPolicyResponse(session *models.Principal, params policyApi.AddPolicyParams) (*models.Policy, *CodedAPIError) {
   566  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   567  	defer cancel()
   568  	if params.Body == nil {
   569  		return nil, ErrorWithContext(ctx, ErrPolicyBodyNotInRequest)
   570  	}
   571  	if strings.Contains(*params.Body.Name, " ") {
   572  		return nil, ErrorWithContext(ctx, ErrPolicyNameContainsSpace)
   573  	}
   574  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   575  	if err != nil {
   576  		return nil, ErrorWithContext(ctx, err)
   577  	}
   578  	// create a MinIO Admin Client interface implementation
   579  	// defining the client to be used
   580  	adminClient := AdminClient{Client: mAdmin}
   581  	policy, err := addPolicy(ctx, adminClient, *params.Body.Name, *params.Body.Policy)
   582  	if err != nil {
   583  		return nil, ErrorWithContext(ctx, err)
   584  	}
   585  	return policy, nil
   586  }
   587  
   588  // policyInfo calls MinIO server to retrieve information of a canned policy.
   589  // policyInfo() takes a policy name, obtains the []byte (represents a string in JSON format)
   590  // and return it as *models.Policy , in the future this will change
   591  // to a Policy struct{} - https://github.com/minio/minio/issues/9171
   592  func policyInfo(ctx context.Context, client MinioAdmin, name string) (*models.Policy, error) {
   593  	policyRaw, err := client.getPolicy(ctx, name)
   594  	if err != nil {
   595  		return nil, err
   596  	}
   597  	policy, err := parsePolicy(name, policyRaw)
   598  	if err != nil {
   599  		return nil, err
   600  	}
   601  	return policy, nil
   602  }
   603  
   604  // getPolicy Statements calls MinIO server to retrieve information of a canned policy.
   605  // and returns the associated Statements
   606  func getPolicyStatements(ctx context.Context, client MinioAdmin, name string) ([]iampolicy.Statement, error) {
   607  	policyRaw, err := client.getPolicy(ctx, name)
   608  	if err != nil {
   609  		return nil, err
   610  	}
   611  
   612  	return policyRaw.Statements, nil
   613  }
   614  
   615  // getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output
   616  func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInfoParams) (*models.Policy, *CodedAPIError) {
   617  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   618  	defer cancel()
   619  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   620  	if err != nil {
   621  		return nil, ErrorWithContext(ctx, err)
   622  	}
   623  	// create a MinIO Admin Client interface implementation
   624  	// defining the client to be used
   625  	adminClient := AdminClient{Client: mAdmin}
   626  	policyName, err := utils.DecodeBase64(params.Name)
   627  	if err != nil {
   628  		return nil, ErrorWithContext(ctx, err)
   629  	}
   630  	policy, err := policyInfo(ctx, adminClient, policyName)
   631  	if err != nil {
   632  		return nil, ErrorWithContext(ctx, err)
   633  	}
   634  	return policy, nil
   635  }
   636  
   637  // SetPolicy calls MinIO server to assign policy to a group or user.
   638  func SetPolicy(ctx context.Context, client MinioAdmin, name, entityName string, entityType models.PolicyEntity) error {
   639  	isGroup := false
   640  	if entityType == models.PolicyEntityGroup {
   641  		isGroup = true
   642  	}
   643  	return client.setPolicy(ctx, name, entityName, isGroup)
   644  }
   645  
   646  // getSetPolicyResponse() performs SetPolicy() and serializes it to the handler's output
   647  func getSetPolicyResponse(session *models.Principal, params policyApi.SetPolicyParams) *CodedAPIError {
   648  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   649  	defer cancel()
   650  	// Removing this section
   651  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   652  	if err != nil {
   653  		return ErrorWithContext(ctx, err)
   654  	}
   655  	// create a MinIO Admin Client interface implementation
   656  	// defining the client to be used
   657  	adminClient := AdminClient{Client: mAdmin}
   658  
   659  	if err := SetPolicy(ctx, adminClient, strings.Join(params.Body.Name, ","), *params.Body.EntityName, *params.Body.EntityType); err != nil {
   660  		return ErrorWithContext(ctx, err)
   661  	}
   662  	return nil
   663  }
   664  
   665  func getSetPolicyMultipleResponse(session *models.Principal, params policyApi.SetPolicyMultipleParams) *CodedAPIError {
   666  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   667  	defer cancel()
   668  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   669  	if err != nil {
   670  		return ErrorWithContext(ctx, err)
   671  	}
   672  	// create a MinIO Admin Client interface implementation
   673  	// defining the client to be used
   674  	adminClient := AdminClient{Client: mAdmin}
   675  
   676  	if err := setPolicyMultipleEntities(ctx, adminClient, strings.Join(params.Body.Name, ","), params.Body.Users, params.Body.Groups); err != nil {
   677  		return ErrorWithContext(ctx, err)
   678  	}
   679  	return nil
   680  }
   681  
   682  // setPolicyMultipleEntities sets a policy to multiple users/groups
   683  func setPolicyMultipleEntities(ctx context.Context, client MinioAdmin, policyName string, users, groups []models.IamEntity) error {
   684  	for _, user := range users {
   685  		if err := client.setPolicy(ctx, policyName, string(user), false); err != nil {
   686  			return err
   687  		}
   688  	}
   689  	for _, group := range groups {
   690  		groupDesc, err := groupInfo(ctx, client, string(group))
   691  		if err != nil {
   692  			return err
   693  		}
   694  		allGroupPolicies := ""
   695  		if len(groups) > 1 {
   696  			allGroupPolicies = groupDesc.Policy + "," + policyName
   697  			s := strings.Split(allGroupPolicies, ",")
   698  			allGroupPolicies = strings.Join(UniqueKeys(s), ",")
   699  		} else {
   700  			allGroupPolicies = policyName
   701  		}
   702  		if err := client.setPolicy(ctx, allGroupPolicies, string(group), true); err != nil {
   703  			return err
   704  		}
   705  	}
   706  	return nil
   707  }
   708  
   709  // parsePolicy() converts from *rawPolicy to *models.Policy
   710  func parsePolicy(name string, rawPolicy *iampolicy.Policy) (*models.Policy, error) {
   711  	stringPolicy, err := json.Marshal(rawPolicy)
   712  	if err != nil {
   713  		return nil, err
   714  	}
   715  	policy := &models.Policy{
   716  		Name:   name,
   717  		Policy: string(stringPolicy),
   718  	}
   719  	return policy, nil
   720  }