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 }